This repository has been archived by the owner on Jun 6, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 141
浅析weex之vdom渲染 #51
Comments
点个赞。 |
膜拜~ |
weex代码目录 变更了吗?js-framework 目录在哪儿,未发现你说的这些文件 |
Weex 本身就是 Native 吧 (虽然有同构 web 版) |
很赞 |
对双向绑定的最牛逼诠释,现在不太明,但是绝对觉厉!👍,支持tree模式渲染。 |
看不懂,但感觉很厉害的样子。 |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
前言
前段时间进行了weex页面尝试, 页面滚动加载渲染得非常流畅, 让H5页面拥有了native般的体验。
如此之利器,让人非常想探一究竟,因此最近进行了js-framwork源码学习(weex开源地址:https://github.com/alibaba/weex),希望能进一步了解其dom渲染机制。
一. 文件结构
weex代码结构如下,重点关注其js-framework实现。
阅读js-framework代码,我整理了一份思维导图。
framework.js是Instance创建的入口,可以从这个文件开始自顶向下地阅读代码,了解其工作原理。可以重点理解它的DOM结构,初始化过程,数据更新过程,下面我也将从这几个方面进行描述。
二. 主要类分析
1. DOM、Listener与EventManager
Weex的DOM结构由
Document
、Element
、Comment
三类组成。Element创建普通节点,Comment用于创建frag block节点。每个节点都有一个唯一的ref
值,可以很方便地在文档中被查询到,同时记录其父节点parentRef
,通过这种’双向链表‘的操作可以方便进行节点拼接和获取。文档树节点Document记录整个DOM的结构,同时在Document上绑定EventManager事件处理器和Listener监听操作处理器。EventManager
记录每个绑定了事件的节点和它对应的事件处理函数,提供事件的添加、删除和触发。Listener
提供了dom操作转化为callNative的能力,通过将每一个操作转化为对应类型的actions,如createBody
、addElement
,并将每一个actions记录updates数组。2. compiler、directive、watcher
Weex复用了 Vue.js 的数据监听和依赖收集的代码实现。通过observer、directive、watcher之间的协作,建立数据(Model)和视图(View)的关联关系:
三. 初始化过程
当我们在浏览器中输入我们的bundle地址,其解析渲染为HTML过程大致可以分解为createInstance->initInstace->run bundle->define->boostrap->create Vm->生命周期函数。可细化为下面这些步骤:
initInstance
: 根据webpack打包后的js代码来定义实例。define
: 解析代码中的__weex_define__("@weex-component/bottom-bar")
定义的component,包含依赖的子组件。并将component记录到customComponentMap[name] = exports
数组中,维护组件与组件代码的对应关系。由于会依赖子组件,因此会被多次调用。bootstrap
:解析代码中的__weex_bootstrap__("@weex-component/30d1c553f95b5f87afb6a1cff70a7bbd")
执行当前页面,提取customComponentMap中记录的组件代码进行初始化。只会执行一次。downgrade
: 检测页面降级配置进行页面降级。initEvents
: 绑定events和lifecycle(init、create、ready)执行的钩子。initScope
: 执行initData()、initComputed、initMethods。初始化data、computed属性和methods,并进行data的observer监听。build
: 根据预留选项opt.replace
进行编译,目前该选项还未被实质使用。编译完成后执行ready的钩子命令,执行ready。compile
: 编译视图。updateActions
: 检测是否有数据更新需要执行。createFinish
: 表明dom结构创建完成,想callQueue队列中添加一个'createFinish'的actions。processCallQueue
: 依次执行队列中的actions,进行节点渲染到页面的过程,为了性能考虑,通过requestAnimationFrame进行分帧渲染。通过初始化过程我们可以得到
init -> 数据监听 -> created -> 视图生成 -> ready
,为了避免重复的视图操作,可在init进行数据的获取,created阶段进行数据的赋值和修改。部分过程细化
1. compile():
首先根据tagert的type类型选择不同的编译方式:数组类型、content类型(占位,可参考special-element)、repeat元素、if元素、function类型元素、子组件元素、内置定义的元素。内置元素类型可在config.js中查看,目前是text、image、container、slider、cell。以内置元素的编译为例,进行body和element节点的编译。在编译的时候会解析节点的attr、class、style、events指令,并进行监听。
从上图可知,weex提供了两种append方式:tree、node。
2. attachTarget()、updateActions()、callTasks():
attachTarget
: 进行节点渲染的时候,将每个append动作细化为具体的actions,置入callQueue队列中。updateActions
: 检测是否有diff,如果有,则执行diff中记录的taskcallTasks
: 调用callNative,根据执行状态判断是否执行callQueue列表中的人物或者置入callQueue队列中。四. 数据更新过程
执行click事件,其中修改了data数据值,执行顺序如下:
![](https://img.alicdn.com/tps/TB1sN8fKVXXXXbJXXXXXXXXXXXX-286-834.png) CallJS响应事件、接受事件,通过eventManager获得事件目标响应函数并fire执行,通过Watcher监听数据修改,如果数据前后不等则将修改更新操作记入diff中,同时通知订阅它的依赖继续收集更新操作。最终执行updateActions完成数据更新操作。 # 总结通过上文分析,可以认为:
以上是个人拙见,本文中描述不正确的地方欢迎指正~
The text was updated successfully, but these errors were encountered: