Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
//检查挂载点是不是<body>元素或者<html>元素
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
const options = this.$options
// 判断渲染函数不存在时
if (!options.render) {
...//构建渲染函数
}
//调用运行时vue的$mount()函数,
return mount.call(this, el, hydrating)
}
前言
vue官方对响应式原理的解释:深入响应式原理
上一节讲了VUE中依赖收集和依赖触发的原理,然鹅对响应式的整体流程我们还是有很多疑问:
为了回答以上的几个问题,我们不得不梳理一波VUE响应式的整体流程了
从实例初始化阶段开始说起
vue源码的 instance/init.js 中是初始化的入口,其中初始化中除了初始化的几个步骤以外,在最后有这样一段 代码:
在初始化结束后,调用$mount()方法将组件挂载挂载至给定的元素vm.$options.el中。
关于$mount的定义在两处可以看到:platforms/web/runtime/index.js、platforms/web/entry-runtime-with-compiler.js
其中runtime/index.js的代码如下:
runtime/index.js是运行时vue的入口,其中定义的$mount()方法是运行时vue的$mount功能,其中主要调用了mountComponent()函数完成挂载。 entry-runtime-with-compiler.js是完整的vue的入口,在运行时vue的$mount基础上加入了编译模版的能力。
编译模版,为挂载提供渲染函数
entry-runtime-with-compiler.js中定义了$mount(),在运行时$mount()的基础上添加了模版编译。代码如下:
entry-runtime-with-compiler.js中的$mount()函数主要做了三件事:
调用运行时vue的$mount()函数,即runtime/index.js中的$mount();
创建渲染函数
上述第二步,若渲染函数不存在时,构建渲染函数,代码如下:
创建渲染函数阶段主要做了两件事:
实现挂载的mountComponent()函数
上一步确保渲染函数render()存在后,就进入到了这正的挂载阶段。前面讲到挂载函数主要在mountComponent()中完成。
mountComponent()函数的定义在src/core/instance/lifecycle.js文件中。代码如下:
mountComponent主要做了三件事:
定义并初始化updateComponent函数:
Watcher类
watcher类的定义在core/observer/watcher.js中,代码如下:
// get方法 get () { ... } // 添加依赖 addDep (dep: Dep) { ... } // 移除废弃观察者;清空newDepIds 属性和 newDeps 属性的值 cleanupDeps () { ... } // 当依赖变化时,触发更新 update () { ... } // 数据变化函数的入口 run () { ... } // 真正进行数据变化的函数 getAndInvoke (cb: Function) { ... } // evaluate () { ... } // depend () { ... }
// teardown () { ... } }
get()中收集依赖
get中的代码如下:
get()函数中主要做了如下几件事:
addDep添加依赖
响应式的整体流程
根据上一章和本章的讲解,总结一下响应式的整体流程: 假设有模版:
至此响应式过程完成。
参考文章:揭开数据响应系统的面纱