三要素
- 响应式:Vue 如何监听到 data 的每个属性变化
- 模版引擎:Vue 的模版如何被解析,指令如何处理
- 渲染:Vue 的模版如何被渲染成 html?以及渲染过程
Vue 的整个实现流程
第一步:解析模版 -> AST 抽象语法树 -> 成 render 函数
- with 用法
- 模版中的信息都被 render 函数包含
- 模版中用到的 data 中属性,都变成了 JS 变量
- 模版中的 v-model、v-for、v-on 都变成了 JS 逻辑
- render 函数执行返回 vnode
第二步:响应式开始监听
- Object.defineProperty,getter、setter
- 将 data 属性代理到 vm(new Vue())的实例对象上
js
var mv = {}
var data = { name: 'fri', age: 26 }
var key, value
for (key in data) {
// 命中闭包。新建一个函数,保证key的独立作用域
;(function(key) {
Object.defineProperty(mv, key, {
get: function() {
return data[key]
},
set: function(newVal) {
data[key] = newVal
}
})
})(key)
}第三步:首次渲染,显示页面,绑定依赖
- 初次渲染,执行 updateComponent,执行
vm._render() - 执行 render 函数,会访问到 vm.list 和 vm.title
- 会被响应式的 get 方法监听到
js
vm._update(vnode) {
const prevVnode = vm._vnode
vm._vnode = vnode
if (!prevVnode) {
vm.$el = vm.__patch__(vm.$el, vnode)
} else {
vm.$el = vm.__patch__(prevVnode, vnode)
}
}
function updateComponent() {
// vm._render 即 上面的 render 函数,返回vnode
vm._update(vm._render())
}为何要监听 get,直接监听 set 不行吗?
- data 中有很多属性,有些被用到,有些不被用到
- 被用到的会走到 get,不被用到不会走到 get
- 未走到 get 中的属性,set 的时候我们也无需关心
- 从而避免不必要的重复渲染
第四步:data 属性变化,触发 rerender
- 修改属性,被响应式的 set 监听到
- set 中执行 updateComponent
- updateComponent 重新执行
vm._render() - 生成的 vnode 和 prevVnode,通过 patch 进行对比
