最近碰到一個需求,需要在Flutter Web專案中載入html。在手機端我們可以使用webview_plugin
外掛載入,但是這個外掛在web上面是無效的。那麼,在Flutter Web中,該如何載入html呢?Flutter為我們提供了一個專門用於web的控制元件:HtmlElementView
。(這裡說點題外話,HtmlElementView的註釋文件裡面有寫,構建html是昂貴操作,如果有等效的Flutter實現可以替換,那麼請儘量不要這麼搞。)
HtmlElementView的基本使用規則
使用這個控制元件必須要注意,使用之前需要註冊!!!
可以在initState()
的時候註冊,當然你也可以在runApp()
的時候就全域性註冊好(個人不建議):
import 'dart:ui' as ui;
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => HtmlElement();
複製程式碼
ui.platformViewRegistry
會報靜態錯誤,不用管,完全不影響你程式碼跑起來。解釋下registerViewFactory()
方法中傳的兩個引數:第一個個人理解是給你需要插入的html片段取一個id名稱,第二個引數則是對應的真正用來載入html的元素。這裡的HtmlElement()
是一個基類,實際書寫的時候應該傳入IFrameElement
、HtmlHtmlElement
、MediaElement
、BodyElement
等等你實際需要的元素。
使用HtmlElementView
時,只需要將已註冊元素對應的id傳進去就可以了:
HtmlElementView(
viewType: 'hello-world-html',
)
複製程式碼
載入URL
載入URL可以使用IFrameElement
(url請寫全了,不要漏掉https
):
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..style.border = 'none'
..src = 'https://www.baidu.com');
複製程式碼
載入本地html檔案
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..style.border = 'none'
..src = '/assets/test2.html');
複製程式碼
載入html string
- 載入比較複雜的混合型html(篇幅比較短的)
如果是各種標籤混合的html,可以使用HtmlHtmlElement
:
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => HtmlHtmlElement()
..style.border = 'none'
..setInnerHtml(html));
複製程式碼
這裡要注意有坑,因為實際專案中使用到的html,含有<img>
、<a href>
之類的標籤是很正常的,但是如果你按照上面的方式載入,圖片、超連結之類的都是沒法顯示的,因為預設的HtmlHtmlElement
是把這些標籤禁用掉的(估計是為了效能吧,畢竟開篇就說了,Flutter其實不希望你直接載入html標籤的),你需要手動開啟允許載入複雜標籤。具體做法是傳入一個validator
引數:
final NodeValidator _validator = NodeValidatorBuilder.common()
..allowElement('img', attributes: ['src'], uriPolicy: _AllowUriPolicy())
..allowElement('a', attributes: ['href'], uriPolicy: _AllowUriPolicy());
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => HtmlHtmlElement()
..style.border = 'none'
..setInnerHtml(html,validator: _validator));
class _AllowUriPolicy implements UriPolicy {
@override
bool allowsUri(String uri) {
return true;
}
}
複製程式碼
- 載入比較複雜的混合型html(篇幅比較長的)
如果是長篇大論的html,如果你用HtmlHtmlElement
載入,就會發現頁面無法滾動。嘗試過與ScrollView
組合展示,比較麻煩,因為如果有圖片一類的資原始檔的話,HtmlElementView
的高度很難計算,反正我沒搞定,如果有大佬有方案歡迎下方留言指導。
嘗試後發現還是需要利用萬能的IFrameElement
,使用srcdoc
的方式載入:
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..style.border = 'none'
..srcdoc = content);
複製程式碼
- 載入單個標籤的html
建議使用輕量型的MediaElement
、BodyElement
、FormElement
、MenuElement
等等。