Vue 首次渲染源码
- 在初始化完结会调用 $mount进行页面挂载
Vue.prototype._init = function (options?: Object) { ... if (vm.$options.el) { // 挂载页面 vm.$mount(vm.$options.el) }}
- 如果是带编译器的版本,会跳转到 $mount的重写办法,多了将模板编译成render函数的操作,详见
// # platforms/web/entry-runtime-with-compiler.jsVue.prototype.$mount = function (){ ... // 调用 web/runtime/index.js下定义的$mount 办法 return mount.call(this, el, hydrating)}
- 原始定义的 $mount办法,解决了el,并调用了 mountComponent
// # platforms/web/runtime/index.jsVue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean): Component { // 为什么这里 && 一下? // 如果带编译器版本,会重写 $mount办法,此时el在重写办法内曾经初始化 // 如果不带编译器版本,浏览器环境下,须要把el转化成 dom,获取dom.innerHTML作为模板 el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating)}
- mountComponent办法定义在 core/instance/lifecycle.js
mountComponent办法解析
- 首先判断 如果开发模式没render函数,且应用运行时版本,则template模板会报错
- 而后执行 callHook(vm,'beforeMount') 钩子
- 而后定义 updateComponent办法,挂载操作的办法,(此处只是定义该办法并未执行)
updateComponent = () => { // _render 调用用户传入的render或编译器生成的render,返回VNode虚构dom // _update将虚构dom转为实在dom vm._update(vm._render(), hydrating)}
- 调用 updateComponent办法在 Watcher实例中
new Watcher(vm, updateComponent, noop, { before () { if (vm._isMounted && !vm._isDestroyed) { callHook(vm, 'beforeUpdate') } }}, true /* isRenderWatcher */)
- 最初执行 callHook(vm,"mounted") 钩子
Watcher类解析
- Watcher类写在 core/observer/watcher.js
- 源码watcher类会调用三次 渲染watcher(以后),计算属性watcher,侦听器watcher
- Watcher类中定义很多属性,lazy属性true 用于计算属性watcher
...get(){ // 每个组件对应一个watcher // 如果组件有嵌套,先渲染外部组件,须要先把父组件watcher保存起来 pushTarget(this) // 这里的 getter就是 传入的 updataComponent value = this.getter.call(vm, vm)}...
updateComponent解析
- 此办法在 core/instance/lifecycle.js下(之前注册的),执行完则首次渲染结束
updateComponent = () => { // 这是个回调,wather外面会调用 // _render 或获取虚构dom _update将虚构dom转为实在dom vm._update(vm._render(), hydrating)}