前语

Webview 资源离线化之后不需求从后端拉取资源,省去了资源加载耗时减少等待时间,用户体会得到了明显提升,但受限于 Webview 的天生限制在某些场景下仍然能感遭到与原生明显的体会落差。比方输入框弹出键盘时的页面卡顿、图片较多的页面内存占用过从后台回来前台时页面被从头加载、WebP 图片支撑碎片化、图片不能跨页共享内存、视频播放组件体会不佳等问题。在 Webview 自身受限的情况下,怎么在体会上向原生靠近是我们不得不面临的问题。假如能将影响用户体会的要害可交互组件用原生组件进行替换能够从根本上处理体会不如原生的问题。这部分内容我称为: WebView原生化

Webview 原生化

Webview 原生化是指把 Webview 内部分占位 DOM 元素用原生组件进行替换,原生组件与原始 Webview 混合便得到了用户看到的最终界面。组件替换有两种方法,一种是在 Webview 的直接上层增加原生视图蒙层,把原生组件增加到蒙层上占位 DOM 对应的方位。另一种是将原生组件增加到 Webiview 烘托时与占位 DOM 对应的组成层(独立出来的原生视图)上,下面会比照两种计划的差异。

微信小程序『同层烘托』技能是怎么回事?

传统计划

计划简介

将原生组件增加到 Webview 上的蒙层是传统计划。思路也很简单,将 Webview 内要用原生替换的组件用占位 DOM 进行封装,占位 DOM 被展现时发送 DOM 的类型、方位、形状等其它信息给到原生。原生在拿到信息后生成对应的原生组件增加到蒙层之上。

微信小程序『同层烘托』技能是怎么回事?

传统计划缺点

原生组件的烘托实践上是彻底独离于 Webview 的烘托流程,乃至是在整个 Webview 的视图之外。这就也意味着:

  • 原生组件的层级是最高的:页面中的其他组件不管设置 z-index 为多少,都无法盖在原生组件上;

  • 部分 CSS 款式无法应用于原生组件;

  • 原生组件无法在 scroll-view、swiper、picker-view、movable-view 中运用:因为假如开发者在可翻滚的DOM区域,插入原生组件作为其子节点,因为原生组件是直接插入到webview外部的层级,与DOM之间没有关联,所以不会跟从移动也不会被削减

微信小程序『同层烘托』技能是怎么回事?

这也就是说当一个原生组件被添另到 Webview 上时它永远处顶层,不会被 Webview 内的弹窗掩盖,在翻滚时原生组件会盖住原本应被显现的区域。

同层烘托

计划简介

原生组件与 DOM 图层在同一层级烘托的方法叫同层烘托。

WKWebview 在进行烘托操作时,会将若干个 DOM 元素混合(Composition)后烘托到原生组成视图(WKComponiitingView)上,假如能将原生组成视图与指定 DOM 进行对应那便能够将原生组件直接增加到组成视图上。

微信小程序『同层烘托』技能是怎么回事?

如上图中选中的图层就是由多个 DOM 组成显现在一起,只需将其间的图片部分独立出一个独自的图层烘托,把原生图片增加到独立出来的原生视图就能够完成同层烘托。其前置条件是:

当把 DOM 节点的 CSS 特点设置为 overflow: scroll (低版本需一起设置 -webkit-overflow-scrolling: touch)之后,原生 WKWebView 会为其生成一个对应的 WKChildScrollView

详细完成流程为:

  1. 小程序前端,在webview内创立一个 DOM 节点并设置其 CSS 特点为 overflow: hidden 且 -webkit-overflow-scrolling: touch;且保证其有个比当前 DOM 大的子 DOM,可增加1px的外边距处理;

  2. 前端通知客户端查找到该 DOM 节点对应的原生 WKChildScrollView 组件;

  3. 将原生组件挂载到该 WKChildScrollView 节点上作为其子 View;

  4. WebKit 内核现已处理了WKChildScrollView与对应DOM 节点之间的层级关系;

前端建创原生视图节点的 DOM 款式示例:

<div class="container cid_1" data-component-type="input" style="width: 200px; height: 40px">
    <div style="width: 101%; height: 101%">&nbsp;</div>
</div>
<style>     
	.container {  /* insert WKChildView in WKWebView */
		overflow: scroll; -webkit-overflow-scrolling: touch;    
 	}
 </style>

把 DOM 节点按前置条件设置之后,WebKit 引擎将图片部分独立出来并插入了一个 WKChildScrollView,只需求在视图树上找到对应的 WKChildScrollView 把原生的 UIImageView 增加到 WKChildScrollView 即可。增加后的原生视图可跟从页面一起翻滚并保留了 DOM 树深度信息,不会掩盖原本应该在上层的组件。

微信小程序『同层烘托』技能是怎么回事?

怎么映射 DOM 到原生视图

独立出来的 WKCompositingView 及其子视图 WKChidScrollView 怎么与 DOM 对应呢?经过打印 WKCompositingView 的 description 特点发现其间包含了类型(div)及 class 信息, 能够经过给每个需求原生化的组件一个唯一 class 名称,前端经过搜集 DOM 特点,把 class 信息传递给原生,原生遍历查找视图树即可。

怎么在原生视图树中查找 「DOM」

WKWebview 烘托出的视图树可能非常复杂层级较多,假如每次都去遍历视图树在快递翻滚的场景可能会呈现功能问题。因为与 DOM 对应的 WKCompositingView 是唯一的,能够经过一个弱引用 Map 去记录每个 class 对应的 WKCompositingView,避免每次都去遍历整个树。

前端原生组件封装

DOM 节点与原生视图的对应关系搞定之后,需求前端封装对应「虚拟组件」。虚拟组件的作用是用来标明方位,大小,形状等信息不用于实践的烘托,烘托经过调用原生的方法(经过 Bridge)由原生处理。此计划正是微信小程序现在运用的计划,现在微信的 canvas、map、animation-view、textarea、cover-view、cover-image、camera、video、live-player、input 等组件都是由原生进行烘托。微信只提供了完成思路,当中的细节处理还需求进一步探索。