跳至主要内容

在 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 中平台视图的行为。
  • 统一两种渲染后端(htmlcanvaskit)在 Web 中渲染平台视图的方式。
  • 在 DOM 中提供一个可预测的位置,允许开发人员可靠地使用 CSS 样式化其平台视图,并使用其他标准 DOM API,例如 querySelectorgetElementById

更改说明

#

Flutter Web 应用现在渲染在一个公共的 阴影根 内,其中 插槽元素 表示平台视图。每个平台视图的实际内容都渲染为上述阴影根的同级元素

之前

#
html
...

<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>

...

之后

#
html
...

<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 做出了假设,并且会中断。

迁移指南

#

代码

#

引擎可能会在控制台中打印一条类似于以下内容的警告消息:

bash
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.

bash
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.widthstyle.height 设置为任何适当的(非空)值。

例如,要使根 html.Element 填充框架分配的所有可用空间,请将其 style.widthstyle.height 属性设置为 '100%'

dart
ui.platformViewRegistry.registerViewFactory(viewType, (int viewId) {
  final html.Element htmlElement = html.DivElement()
    // ..other props
    ..style.width = '100%'
    ..style.height = '100%';
  // ...
  return htmlElement;
});

如果使用其他技术来布局平台视图(如 inset: 0),则 widthheight 的值为 auto 就足以停止警告。

阅读有关 CSS widthCSS height 的更多信息。

测试

#

在此更改之后,用户的测试代码不需要深入检查应用阴影根的内容。所有平台视图内容都将作为 flt-glass-pane 的直接子元素放置,并包装在 flt-platform-view 元素中。

避免查看 flt-glass-pane 阴影根内部,它被认为是“私有实现细节”,其标记可能会随时更改,恕不另行通知。

(有关上面描述的“迁移”的示例,请参阅下面的相关 PR。)

时间线

#

包含在版本中:2.3.0-16.0.pre
在稳定版中发布:2.5

参考文献

#

设计文档

相关问题

相关 PR