作者:马倩
转发链接:
https://mp.weixin.qq.com/s/LlZB6ZC5NkxnBj-C5iZNnA
Kbone原理解析官方介绍“Kbone 是一个致力于微信小程序和 Web 端同构的解决方案 。”
Web端框架基本原理首先我们来看下普通Web端框架,以Vue框架为例,一份Vue模板对应一个组件,在代码构建阶段编译成调用Dom接口的JS函数,执行此JS函数就会创建出组件对应的Dom树,从而渲染到浏览器页面上 。
文章插图
然而,小程序是双线程的,并没有Dom树的概念,逻辑层和视图层完全分离,逻辑层是一个纯粹的JSCore,开发者可以编写JS脚本,但是无法直接调用Dom/Bom的api, 没有任何浏览器相关的实现 。
在小程序中,视图层和逻辑层的交互是通过数据和时间驱动的 。
因此,要实现跨端同构,问题是:怎么将web端代码转为小程序代码?
业界常规做法目前业界流行的第三方跨端框架们,常规做法都是:静态编译兼容 。
文章插图
原理是把代码语法分析一遍,然后将其中的模板部分翻译成对应的跨端需求的模板(微信小程序、支付宝小程序、H5、App等) 。
静态编译最大的局限性是无法保证转换的完整性,因为Vue模板和WXML模板的语法并不是直接对等的,Vue的特性设计也和小程序的设计无法划等号,这自然就导致了部分Vue特性的丢失 。
比如像Vue中的v-html指令、ref获取Dom节点、过滤器等就通通用不了 。
除了Vue自身的特性外,一些原本依赖Dom/Bom接口的Vue插件也无法使用,例如Vue-Router 。
Kbone的做法【Kbone原理详解与小程序技术选型】Kbone是通过提供 适配器 的方式来实现同构,即运行时兼容,而非静态编译 。
Kbone的适配器核心包含两个部分:
miniprogram-render:仿造Dom/Bom接口,构造仿造Dom树;
miniprogram-element: 监听仿造Dom树变化,渲染到页面,同时监听用户行为,触发事件 。
仿造Dom树和浏览器的运行时对比:
仿造Dom树:利用内置组件和自定义组件的自引用来进行递归,创建组件树 。
如图,自定义custom-dom为递归自引用组件:
文章插图
递归的终止条件是遇到特定节点、文本节点或者children空节点 。
在创建出组件树后,将Dom节点和自定义组件实例进行绑定,以便后续的Dom更新和操作 。
文章插图
kbone这里还对节点数进行了优化:
如果一个dom节点对应一个自定义组件的话,就会创建很多自定义组件,这样会很浪费开销,这里做了子树的合并,也就是说3层才创建一个自定义组件,节省开销 。
优化前:17个dom=17个自定义组件;优化后:17个dom=4个自定义组件,蓝色那个是单节点,会合并到上面的树;
文章插图
dom 子数作为自定义组件渲染的层级数是可以通过配置传入,理论上层级越多,使用自定义组件数量越少,性能也就越好 。
一颗很大的 Dom 树,一次性 setData 到视图层,可能会超过 setData 的大小限制(1024kB),拆分成多颗子 Dom 树,然后分批的 setData 到视图层,可以节省开销 。
事件监听小程序的事件是视图层到逻辑层的通讯方式,事件绑定在组件上,当被触发时,就会执行逻辑层中对应的事件处理函数 。
小程序的捕获冒泡是在视图层view端,因此逻辑层在整个捕获冒泡流程中各个节点接收到的事件不是同一个对象,小程序事件的捕获冒泡和阻止冒泡等操作必须在WXML模板中声明,无法使用接口实现 。
文章插图
为了能够让web端和小程序端的事件系统行为一致,kbone除了仿造了一份Dom树外,也把整个事件系统仿造了一份,即在仿造Dom树上进行捕获冒泡 。
当自定义组件监听到用户的操作后,就将事件发往仿造Dom树,后续自定义组件监听到的同一个事件的冒泡就直接忽略 。
当触发该节点,仿造Dom树接收到事件后,再进行捕获和冒泡,让事件在各个节点触发 。
文章插图
Kbone的优势