canvas2d接⼝⽀持同层渲染且性能更佳,建议切换使⽤。
⼩程序同层渲染原理剖析[转载]
打开⼩程序后,发现有个warning
canvas 2d 接⼝⽀持同层渲染且性能更佳,建议切换使⽤。
以上是官⽹给出的⽅案。
还记得在开发的过程,⼀开始是这样的,在UI⾥渲染了⼀个⼆维码的图⽚,
然后点击⼆维码图⽚以后呢,会弹出⼀个对话框。
我发现这样对话框在弹的时候,竟然原来界⾯的⼆维码图⽚也会在上⾯,感觉体验特别不好。
原来是渲染的⽅式不⼀样导致。下⾯的⽂章对⼩程序同层渲染原理剖析,感觉不错,所以整体转载,
万⼀那天打不开了,还可以看看转的。
本⽂转⾃:
众所周知,⼩程序当中有⼀类特殊的内置组件——原⽣组件,这类组件有别于 WebView 渲染的内置组件,他们是交由原⽣客户端渲染的。原⽣组件作为 Webview 的补充,为⼩程序带来了更丰富的特性和更⾼的性能,但同时由于脱离 Webview 渲染也给开发者带来了不⼩的困扰。在⼩程序引⼊「同层渲染」之前,原⽣组件的层级总是最⾼,不受z-index属性的控制,⽆法与view、image等内置组件相互覆盖,cover-view和cover-image组件的出现⼀定程度上缓解了覆盖的问题,同时为了让原⽣组件能被嵌套在swiper、scroll-view等容器内,⼩程序在过去也
推出了⼀些临时的解决⽅案。但随着⼩程序⽣态的发展,开发者对原⽣组件的使⽤场景不断扩⼤,原⽣组件的这些问题也⽇趋显现,为了彻底解决原⽣组件带来的种种限制,我们对⼩程序原⽣组件进⾏了⼀次重构,引⼊了「同层渲染」。
相信已经有不少开发者已经在⽇常的⼩程序开发中使⽤了「同层渲染」的原⽣组件,那么究竟什么是「同层渲染」?它背后的实现原理是怎样的?它是解决原⽣组件限制的银弹吗?本⽂将会为你⼀⼀解答这些问题。
什么是「同层渲染」?
⾸先我们先来了解⼀下⼩程序原⽣组件的渲染原理。我们知道,⼩程序的内容⼤多是渲染在 WebView 上的,如果把 WebView 看成单独的⼀层,那么由系统⾃带的这些原⽣组件则位于另⼀个更⾼的层级。
两个层级是完全独⽴的,因此⽆法简单地通过使⽤z-index控制原⽣组件和⾮原⽣组件之间的相对层级。正如下图所⽰,⾮原⽣组件位于 WebView 层,⽽原⽣组件及cover-view与cover-image则位于另⼀个较⾼的层级:
那么「同层渲染」顾名思义则是指通过⼀定的技术⼿段把原⽣组件直接渲染到 WebView 层级上,此时「原⽣组件层」已经不存在,原⽣组
件此时已被直接挂载到 WebView 节点上。你⼏乎可以像使⽤⾮原⽣组件⼀样去使⽤「同层渲染」的原⽣组件,⽐如使⽤view、image覆盖原⽣组件、使⽤z-index指定原⽣组件的层级、把原⽣组件放置在scroll-view、swiper、movable-view等容器内,通过WXSS设置原⽣组件的样式等等。启⽤「同层渲染」之后的界⾯层级如下图所⽰:
「同层渲染」原理
你⼀定也想知道「同层渲染」背后究竟采⽤了什么技术。只有真正理解了「同层渲染」背后的机制,才能更⾼效地使⽤好这项能⼒。实际上,⼩程序的同层渲染在 iOS 和 Android 平台下的实现不同,因此下⾯分成两部分来分别介绍两个平台的实现⽅案。
iOS 端
⼩程序在 iOS 端使⽤ WKWebView 进⾏渲染的,WKWebView 在内部采⽤的是分层的⽅式进⾏渲染,它会将 WebKit 内核⽣成的Compositing Layer(合成层)渲染成 iOS 上的⼀个 WKCompositingView,这是⼀个客户端原⽣的 View,不过可惜的是,内核⼀般会将多个 DOM 节点渲染到⼀个 Compositing Layer 上,因此合成层与 DOM 节点之间不存在⼀对⼀的映射关系。不过我们发现,当把⼀个 DOM 节点的 CSS 属性设置为overflow: scroll(低版本需同时设置-webkit-overflow-scrolling: touch)之后,WKWebView 会为其⽣成⼀
个WKChildScrollView,与 DOM 节点存在映射关系,这是⼀个原⽣的UIScrollView的⼦类,也就是说 WebView ⾥的滚动实际上是由真正的原⽣滚动组件来承载的。WKWebView 这么做是为了可以让 iOS 上的 WebView 滚动有更流畅的体验。虽说WKChildScrollView也是原⽣组件,但WebKit 内核已经处理了它与其他 DOM 节点之间的层级关系,因此你可以直接使⽤ WXSS 控制层级⽽不必担⼼遮挡的问
题。
⼩程序 iOS 端的「同层渲染」也正是基于WKChildScrollView实现的,原⽣组件在 attached 之后会直接挂载到预先创建好
的WKChildScrollView容器下,⼤致的流程如下:
1. 创建⼀个 DOM 节点并设置其 CSS 属性为overflow: scroll且-webkit-overflow-scrolling: touch;
2. 通知客户端查到该 DOM 节点对应的原⽣WKChildScrollView组件;
3. 将原⽣组件挂载到该WKChildScrollView节点上作为其⼦ View。
通过上述流程,⼩程序的原⽣组件就被插⼊到WKChildScrollView了,也即是在步骤1创建的那个 DOM 节点对应的原⽣ ScrollView 的⼦节点。此时,修改这个 DOM 节点的样式属性同样也会应⽤到原⽣组件上。因此,「同层渲染」的原⽣组件与普通的内置组件表现并⽆⼆致。
Android 端
position标签属性⼩程序在 Android 端采⽤ chromium 作为 WebView 渲染层,与 iOS 不同的是,Android 端的 WebVie
w 是单独进⾏渲染⽽不会在客户端⽣成类似 iOS 那样的 Compositing View (合成层),经渲染后的 WebView 是⼀个完整的视图,因此需要采⽤其他的⽅案来实现「同层渲染」。经过我们的调研发现,chromium ⽀持 WebPlugin 机制,WebPlugin 是浏览器内核的⼀个插件机制,主要⽤来解析和描述embed 标签。Android 端的同层渲染就是基于embed标签结合 chromium 内核扩展来实现的。
Android 端「同层渲染」的⼤致流程如下:
1. WebView 侧创建⼀个embed DOM 节点并指定组件类型;
2. chromium 内核会创建⼀个WebPlugin实例,并⽣成⼀个RenderLayer;
3. Android 客户端初始化⼀个对应的原⽣组件;
4. Android 客户端将原⽣组件的画⾯绘制到步骤2创建的RenderLayer所绑定的SurfaceTexture上;
5. 通知 chromium 内核渲染该RenderLayer;
6. chromium 渲染该embed节点并上屏。
这样就实现了把⼀个原⽣组件渲染到 WebView 上,这个流程相当于给 WebView 添加了⼀个外置的插件,如果你有留意 Chrome 浏览器上的 pdf 预览,会发现实际上它也是基于<embed />标签实现的。
这种⽅式可以⽤于 map、video、canvas、camera 等原⽣组件的渲染,对于 input 和 textarea,采⽤的⽅案是直接对 chromium 的组件进⾏扩展,来⽀持⼀些 WebView 本⾝不具备的能⼒。
对⽐ iOS 端的实现,Android 端的「同层渲染」真正将原⽣组件视图加到了 WebView 的渲染流程中且 embed 节点是真正的 DOM 节点,理
论上可以将任意 WXSS 属性作⽤在该节点上。Android 端相对来说是更加彻底的「同层渲染」,但相应的重构成本也会更⾼⼀些。「同层渲染」 Tips
通过上⽂我们已经了解了「同层渲染」在 iOS 和 Android 端的实现原理。Android 端的「同层渲染」是基于 chromium 内核开发的扩展,可以看成是 webview 的⼀项能⼒,⽽ iOS 端则需要在使⽤过程中稍加注意。以下列出了若⼲注意事项,可以帮助你避免踩坑:
Tips 1. 不是所有情况均会启⽤「同层渲染」
需要注意的是,原⽣组件的「同层渲染」能⼒可能会在特定情况下失效,⼀⽅⾯你需要在开发时稍加注意,另⼀⽅⾯同层渲染失败会触
发bindrendererror事件,可在必要时根据该回调做好 UI 的 fallback。根据我们的统计,⽬前同层失败率很低,也不需要太过于担⼼。
对 Android 端来说,如果⽤户的设备没有⾃研的chromium内核,则会⽆法切换⾄「同层渲染」,此时会在组件初始化阶段触
发bindrendererror。⽽ iOS 端的情况会稍复杂⼀些:如果在基础库创建同层节点时,节点发⽣了 WXSS 变化从⽽引起 WebKit 内核重排,此时可能会出现同层失败的现象。解决⽅法:应尽量避免在原⽣组件上频繁修改节点的 WXSS 属性,尤其要尽量避免修改节点的position属性。如需对原⽣组件进⾏变换,强烈推荐使⽤transform⽽⾮修改节点的position属性。
Tips 2. iOS 「同层渲染」与 WebView 渲染稍有区别
上⽂我们已经了解了 iOS 端同层渲染的原理,实际上,WebKit 内核并不感知原⽣组件的存在,因此并⾮所有的 WXSS 属性都可以在原⽣组件上⽣效。⼀般来说,定位 (position / margin / padding) 、尺⼨ (width / height) 、transform (scale / rotate / translate) 以及层级 (z-index) 相关的属性均可⽣效,在原⽣组件外部的属性 (如 shadow、border) ⼀般也会⽣效。但如需对组件做裁剪则可能会失败,例如:border-radius属性应⽤在⽗节点不会产⽣圆⾓效果。
Tips 3. 「同层渲染」的事件机制
启⽤了「同层渲染」之后的原⽣组件相⽐于之前的区别是原⽣组件上的事件也会冒泡,意味着,⼀个
原⽣组件或原⽣组件的⼦节点上的事件也会冒泡到其⽗节点上并触发⽗节点的事件监听,通常可以使⽤catch来阻⽌原⽣组件的事件冒泡。
Tips 4. 只有⼦节点才会进⼊全屏
有别于⾮同层渲染的原⽣组件,像video和live-player这类组件进⼊全屏时,只有其⼦节点会被显⽰。
总结
阅读本⽂之后,相信你已经对⼩程序原⽣组件的「同层渲染」有了更深⼊的理解。同层渲染不仅解决了原⽣组件的层级问题,同时也让原⽣组件有了更丰富的展⽰和交互的能⼒。下表列出的原⽣组件都已经⽀持了「同层渲染」,其他组件( textarea、camera、webgl 及 input)也会在近期逐步上线。现在你就可以试试⽤「同层渲染」来优化你的⼩程序了。
⽀持同层渲染的原⽣组件最低版本
video v2.4.0
map v2.7.0
(新接⼝)v2.9.0
live-player v2.9.1
live-pusher v2.9.1
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论