在 Web 中使用 HTML 插槽渲染平台视图
摘要
#Flutter 现在将所有 Web 平台视图渲染到 DOM 的一致位置,作为 flt-glass-pane
的直接子元素(无论渲染后端是 html
还是 canvaskit
)。然后,平台视图使用标准 HTML 功能“插入”到应用 DOM 的正确位置。
在此更改之前,Flutter Web 会更改渲染的平台视图内容的样式以将其定位/调整大小到可用空间。这种情况不再存在。用户现在可以决定如何利用框架为其平台视图分配的空间。
上下文
#Flutter 框架经常调整其渲染树以优化最终每帧进行的绘制操作。在 Web 中,这些渲染树更改通常会导致 DOM 操作。
Flutter Web 过去会将其平台视图(HtmlElementView
小部件)直接渲染到 DOM 中的对应位置。
将某些 DOM 元素用作某些 DOM 操作的“目标”会导致这些元素丢失其内部状态。在实践中,这意味着 iframe
标记将重新加载,video
播放器可能会重新启动,或者可编辑表单可能会丢失其编辑内容。
Flutter 现在使用 插槽元素 在单个应用范围的 阴影根 内渲染平台视图。可以向 Shadow DOM 添加/删除/移动插槽元素,而不会影响底层插槽内容(在固定位置渲染)
此更改是为了
- 稳定 Flutter Web 中平台视图的行为。
- 统一两种渲染后端(
html
和canvaskit
)在 Web 中渲染平台视图的方式。 - 在 DOM 中提供一个可预测的位置,允许开发人员可靠地使用 CSS 样式化其平台视图,并使用其他标准 DOM API,例如
querySelector
和getElementById
。
更改说明
#Flutter Web 应用现在渲染在一个公共的 阴影根 内,其中 插槽元素 表示平台视图。每个平台视图的实际内容都渲染为上述阴影根的同级元素。
之前
#...
<flt-glass-pane>
...
<div id="platform-view">Contents</div> <!-- canvaskit -->
<!-- OR -->
<flt-platform-view>
#shadow-root
| <div id="platform-view">Contents</div> <!-- html -->
</flt-platform-view>
...
</flt-glass-pane>
...
之后
#...
<flt-glass-pane>
#shadow-root
| ...
| <flt-platform-view-slot>
| <slot name="platform-view-1" />
| </flt-platform-view-slot>
| ...
<flt-platform-view slot="platform-view-1">
<div id="platform-view">Contents</div>
</flt-platform-view>
...
</flt-glass-pane>
...
在此更改之后,当框架需要移动 DOM 节点时,它会在 flt-platform-view-slot
上进行操作,这些节点仅包含一个 slot
元素。插槽投影在 flt-platform-view
元素中定义的内容在阴影根之外。flt-platform-view
元素永远不会成为框架来自 DOM 操作的目标,从而防止重新加载问题。
从应用的角度来看,此更改是透明的。但是,这被认为是重大更改,因为某些测试对 Flutter Web 应用的内部 DOM 做出了假设,并且会中断。
迁移指南
#代码
#引擎可能会在控制台中打印一条类似于以下内容的警告消息:
Height of Platform View type: [$viewType] may not be set. Defaulting to `height: 100%`.
Set `style.height` to any appropriate value to stop this message.
或
Width of Platform View type: [$viewType] may not be set. Defaulting to `width: 100%`.
Set `style.width` to any appropriate value to stop this message.
以前,由 PlatformViewFactory
函数 返回的内容由框架调整大小和定位。相反,Flutter 现在调整 <flt-platform-view-slot>
的大小和位置,它是插槽内容投影到的插槽的父元素。
要停止上述警告,平台视图需要将其根元素的 style.width
和 style.height
设置为任何适当的(非空)值。
例如,要使根 html.Element
填充框架分配的所有可用空间,请将其 style.width
和 style.height
属性设置为 '100%'
ui.platformViewRegistry.registerViewFactory(viewType, (int viewId) {
final html.Element htmlElement = html.DivElement()
// ..other props
..style.width = '100%'
..style.height = '100%';
// ...
return htmlElement;
});
如果使用其他技术来布局平台视图(如 inset: 0
),则 width
和 height
的值为 auto
就足以停止警告。
阅读有关 CSS width
和 CSS height
的更多信息。
测试
#在此更改之后,用户的测试代码不需要深入检查应用阴影根的内容。所有平台视图内容都将作为 flt-glass-pane
的直接子元素放置,并包装在 flt-platform-view
元素中。
避免查看 flt-glass-pane
阴影根内部,它被认为是“私有实现细节”,其标记可能会随时更改,恕不另行通知。
(有关上面描述的“迁移”的示例,请参阅下面的相关 PR。)
时间线
#包含在版本中:2.3.0-16.0.pre
在稳定版中发布:2.5
参考文献
#设计文档
相关问题
相关 PR
- flutter/engine#25747:引入此功能。
- flutter/flutter#82926:调整
flutter
测试。 - flutter/plugins#3964:对
plugins
代码进行调整。 - flutter/packages#364:对
packages
代码进行调整。
除非另有说明,否则本网站上的文档反映了 Flutter 的最新稳定版本。页面上次更新于 2024-04-04。 查看源代码 或 报告问题。