Skip to content

三要素

  • 响应式:Vue 如何监听到 data 的每个属性变化
  • 模版引擎:Vue 的模版如何被解析,指令如何处理
  • 渲染:Vue 的模版如何被渲染成 html?以及渲染过程

Vue 的整个实现流程

第一步:解析模版 -> AST 抽象语法树 -> 成 render 函数

  1. with 用法
  2. 模版中的信息都被 render 函数包含
  3. 模版中用到的 data 中属性,都变成了 JS 变量
  4. 模版中的 v-model、v-for、v-on 都变成了 JS 逻辑
  5. render 函数执行返回 vnode

第二步:响应式开始监听

  1. Object.defineProperty,getter、setter
  2. 将 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)
}

第三步:首次渲染,显示页面,绑定依赖

  1. 初次渲染,执行 updateComponent,执行 vm._render()
  2. 执行 render 函数,会访问到 vm.list 和 vm.title
  3. 会被响应式的 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

  1. 修改属性,被响应式的 set 监听到
  2. set 中执行 updateComponent
  3. updateComponent 重新执行 vm._render()
  4. 生成的 vnode 和 prevVnode,通过 patch 进行对比

共 20 个模块,1301 篇 Markdown 文档。