Flutter web 与原js结合
起因
由于Flutter最近很火,团队在做flutter-dart的全平台尝试。
对于Web这块,由于我们本身有很多react组件的积累,所以想在flutter web上直接使用原有的JS。
一开始,因为flutter web的语法可以直接和js语法对标,所以感觉不是什么困难的事情。
但是最终发现了有个1.20.4版本flutter,暂时还无法逾越的坑。
shadow dom
简单说,flutter 在创建web的platform view时,会在node前添加# showdow-root(open)
该标记会将子Node作为一个单独的绘制区域,导致导入进来的js无法直接获取到shadow root中的子节点,结果无法替换对应的dom。
尝试解决
1、官方的回答
https://github.com/flutter/flutter/issues/50452
总结就是,flutter官方后续可能会开放一个shadow-root创建成功的回调,也可能是直接将整个绘制成外面加一个shadow-root,让大家可以自定义style、class啥的。现在已经提上日程,但是开发者度假中,等回来再说…希望你看到这篇文章的时候该问题已经解决。
2、尝试使用<slot>
Element _iFrame = DivElement()
..id = 'container'
..style.border = '1'
..append(DivElement()..id = 'app' ..style.border='1')
..appendHtml('''<slot name="app"></slot>''')
..append(ScriptElement()
..type = "text/javascript"
..src = "/js/app.js"
);
想用light dom去替换相应的节点。
结论:失败,提示slot标签是不被允许添加的。
3、最后只能修改js,先获取shadowRoot
将原来获取标签的方法,修改为用shadowRoot获取
var shadowRoot = document.getElementsByTagName("flt-platform-view")[0].shadowRoot;
i.i.render(i.i.createElement(u, null), shadowRoot.getElementById("app"))
指标不治本,先凑合用。
总结
虽然3解决这个问题,但是当一个页面有多个HtmlElementView时,就要修改每一个js,这个对于复用来说很不好,所以建议大家flutter web要用就纯粹用flutter,除了难实现的三方库。
2020-3-4 更新
Flutter 在3月4日添加了新的更新,<slot>
标签已经可用。
相关文档:
https://docs.google.com/document/d/1U6aCSuzQsFpOP8_OseL-fwl2-MC2bxJAsgt2R_-sC30/edit
This makes applying the above technique to Flutter Web relatively straightforward:
Attach a Shadow Root to the flt-scene-host element.
Render flt-scene and all its descendants inside said ShadowDOM.
When a platform view of “viewType” (defined by the user) is rendered:
A tag with the passed-in name (viewType) is added into the right position of the scene by the framework (this’ll end up inside the ShadowDOM of the flt-scene-host).
The actual contents of the platform view get a “slot” attribute added to them, with the value of viewType, and rendered as a child of the flt-scene-host element (“a sibling” to its ShadowDOM).
Ensure both the HTML and CanvasKit backends render platform views the same way.
Most of the lifecycle and DOM attachment logic for platform views should be reusable. The main difference would only be the creation of the elements.