同层渲染

28 3月

同层渲染是为了解决普通组件与原生组件不相容的问题。原生组件会覆盖在普通组件之上,遮挡住普通组件,而且不会随着页面滚动而滚动。

微信团队为了解决这个问题,推出了cover-viewcover-image可以覆盖在原生组件之上,但它俩限制太多,里面不能放置普通组件。在基础库2.9.0之后,微信团队推出了同层渲染,原生组件可以像普通组件一样去使用,可以将原生组件放在普通组件下面。

Android同层渲染

小程序在Android端,采用Chromium浏览器内核实现了Webview渲染层,Chromium浏览器内核提供了WebPlugin机制,主要用来解析和描述embed标签。

Chromium内核为每个embed标签,创建一个WebPlugin实例,并单独生成一个RenderLayer渲染层,可以直接渲染到最终的视图上。

自定义embed标签都是独立的,可以像其他组件一样,用样式控制位置与层级。

iOS同层渲染

iOS用的是Webkit内核实现的WKWebview,内部采用的是分层方式的渲染,然后用Webkit内核生成的合成层,渲染成iOS上一个WKCompositingView原生View。问题是WKCompositingView会将多个DOM节点渲染到同一个合成层上,导致DOM节点和渲染层之间不是一对一关系,就无法控制与原生组件间上下层的关系。

WKWebview里将CSS属性overflow等于scroll之后,WKWebview会为它生成一个WKChildScrollView来改善滚动的性能。微信团队发现将原生组件插入到WKChildScrollView容器里就可以控制上下层之间的关系了。在需要插入原生组件的地方设置一个style为overflow:scroll 的前端滚动元素,这时WKWebview会创建一个WKChildScrollView,客户端将原生组件插入到WKChildScrollView的subview中,实现了原生组件和前端组件的同层渲染。

为什么不使用WKCompositingView作为原生组件插入的容器?因为WKCompositingView是经过Webkit生成的合成层渲染出来的,与前端DOM不一定是一一对应的关系。所以无法控制具体插入到前端哪个部分。

不适用同层渲染

组件在应用同层渲染时可能会失败,例如页面滚动时canvas组件不一起滚动。开发时通过bindrendererror事件,监听同层渲染是否出现了错误。

并不是所有WXSS样式属性都可以在原生组件上生效,例如定位样式,position,margin,padding,width,height,transform,z-index,shadow等都能生效,但对组件进行裁剪的样式可能会失败,例如border-radius可能就无法产生圆角效果。

由于使用了非常规的开发机制,在iOS上DOM的事件派发机制也可能受到影响。启用同层渲染后,作为WKChildScrollView子组件的原生组件的事件也会冒泡,冒泡到与原生组件没有父子关系的上层组件上去,此时可以使用catch代替bind来阻止事件冒泡。

也不是所有原生组件都支持同层渲染,例如camera,input,textarea就不支持,具体参照官网

实际应用

直播时可以将原生组件live-player设置为全屏,放置到普通UI组件下面,以实现全屏直播的效果。

发表评论

邮箱地址不会被公开。 必填项已用*标注