上一篇文章我们介绍了 Vue2模版编译原理,这一章我们的目标是弄清楚模版 template和响应式数据是如何渲染成最终的DOM。数据更新驱动视图变化这部分后期会单独讲解
我们先看一下模版和响应式数据是如何渲染成最终DOM 的流程
Vue初始化
new Vue发生了什么
Vue入口构造函数
highlighter- reasonml
function Vue(options) { this._init(options) // options就是用户的选项 ... } initMixin(Vue) // 在Vue原型上扩展初始化相关的方法,_init、$mount 等 initLifeCycle(Vue) // 在Vue原型上扩展渲染相关的方法,_render、_c、_v、_s、_update 等 export default Vue
initMixin、initLifeCycle方法
highlighter- reasonml
export function initMixin(Vue) { Vue.prototype._init = function (options) { const vm = this vm.$options = options // 将用户的选项挂载到实例上 // 初始化数据 initState(vm) if (options.el) { vm.$mount(options.el) } } Vue.prototype.$mount = function (el) { const vm = this el = document.querySelector(el) let ops = vm.$options // 这里需要对模板进行编译 const render = compileToFunction(template) ops.render = render // 实例挂载 mountComponent(vm, el) } } export function initLifeCycle(Vue) { Vue.prototype._render = function () {} // 渲染方法 Vue.prototype._c = function () {} // 创建节点虚拟节点 Vue.prototype._v = function () {} // 创建文本虚拟节点 Vue.prototype._s = function () {} // 处理变量 Vue.prototype._update = function () {} // 初始化元素 和 更新元素 }
在 initMixin 方法中,我们重点关注 compileToFunction模版编译 和 mountComponent实例挂载 2个方法。我们已经在上一篇文章详细介绍过 compileToFunction 编译过程,接下来我们就把重心放在 mountComponent 方法上,它会用到在 initLifeCycle 方法给Vue原型上扩展的方法,在 render 和 update章节会做详细讲解
实例挂载
mountComponent 方法主要是 实例化了一个渲染 watcher,updateComponent 作为回调会立即执行一次。watcher 还有一个其他作用,就是当响应式数据发生变化时,也会通过内部的 update方法执行updateComponent 回调。
现在我们先无需了解 watcher 的内部实现及其原理,后面会作详细介绍
vm._render 方法会创建一个虚拟DOM(即以 VNode节点作为基础的树),vm._update 方法则是把这个虚拟DOM 渲染成一个真实的 DOM 并渲染出来
highlighter- reasonml
export function mountComponent(vm, el) { // 这里的el 是通过querySelector获取的 vm.$el = el const updateComponent = () => { // 1.调用render方法创建虚拟DOM,即以 VNode节点作为基础的树 const vnode