使用 HTML 插槽在 Web 中渲染平臺檢視
概述
#Flutter 現在會將所有 Web 平臺檢視渲染到 DOM 的一個固定位置,作為 flt-glass-pane 的直接子元素(無論使用何種渲染後端:html 還是 canvaskit)。然後,平臺檢視會透過標準的 HTML 功能 "插入" 到應用程式 DOM 的正確位置。
在此更改之前,Flutter Web 會修改平臺檢視渲染內容的樣式,以將其定位/調整到可用空間。現在情況不再是這樣了。使用者現在可以決定他們希望如何利用框架分配給其平臺檢視的空間。
背景
#Flutter 框架會頻繁調整其渲染樹,以最佳化每幀最終執行的繪製操作。在 Web 端,這些渲染樹的變化通常會導致 DOM 操作。
Flutter Web 過去會將平臺檢視(HtmlElementView 小部件)直接渲染到 DOM 中對應的位置。
將某些 DOM 元素用作某些 DOM 操作的 "目標" 會導致這些元素丟失其內部狀態。實際上,這意味著 iframe 標籤會重新載入,video 播放器可能會重啟,或者可編輯表單可能會丟失其編輯內容。
Flutter 現在使用 slot 元素 在一個全域性應用程式的 Shadow DOM 中渲染平臺檢視。Slot 元素可以被新增到/移除/移動到 Shadow DOM 的不同位置,而不會影響底層的插槽內容(這些內容在一個固定的位置渲染)。
此更改是為了:
- 穩定 Flutter Web 中平臺檢視的行為。
- 統一兩種渲染後端(
html和canvaskit)在 Web 中渲染平臺檢視的方式。 - 提供一個可預測的 DOM 位置,使開發人員能夠可靠地使用 CSS 來設定其平臺檢視的樣式,並使用其他標準的 DOM API,如
querySelector和getElementById。
變更說明
#Flutter Web 應用程式現在渲染在一個通用的 Shadow DOM 中,其中 slot 元素 代表平臺檢視。每個平臺檢視的實際內容被渲染為該 Shadow DOM 的同級元素。
之前
#...
<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 元素。該 slot 將 flt-platform-view 元素中定義的內容 "投射" 到 Shadow DOM 之外。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 設定為任何適當的(非 null)值。
例如,要使根 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 的資訊。
測試
#在此更改之後,使用者的測試程式碼不需要深入檢查應用程式的 Shadow DOM 內容。所有平臺檢視內容都將作為 flt-glass-pane 的直接子元素放置,並封裝在 flt-platform-view 元素中。
避免檢視 flt-glass-pane Shadow DOM 的內部,這被認為是“私有實現細節”,其標記可能會隨時更改,恕不另行通知。
(參見下面的相關 PRs,瞭解上述 "遷移" 的示例)。
時間線
#已登陸版本:2.3.0-16.0.pre
穩定版本:2.5
參考資料
#設計文件
相關問題
相關 PR
- flutter/engine#25747: 引入該功能。
- flutter/flutter#82926: 調整
flutter測試。 - flutter/plugins#3964: 調整
plugins程式碼。 - flutter/packages#364: 調整
packages程式碼。