这里选用的是runtime and compile版本的vue,首先用mount变量缓存起来Vue的原型上挂载的$mount方法,然后又重新定义了$mount方法。这个$mount方法其实是在引入的./runtime/index文件中定义的,为什么要重新定义一遍,因为runtime only 版本是没有这个逻辑的,实际上是给runtime only版本用的 当在初始化执行vm.$mount(vm.$options.el)挂载的时候,实际上调用的重写后的$mount函数,这个函数首先对el参数做了一个处理,el可以是一个字符串也可以是一个element,这里调用了query方法 query方法实际上调用了原生的api,如果el是一个字符串,就调用querySelector方法,如果找不到的话,就会报一个错,返回一个空的div,否则不是字符串,已经是一个dom对象 ,那就直接return就可以了 拿到el之后,这里已经被转成的dom对象,,然后又做了一个简单的判断el如果是一个body或这是一个文档元素就会报一个错,Vue不能直接挂载到html和body上,因为它是会覆盖的,如果挂载的话会把整个body覆盖,整个html就不对 然后拿到options,然后判断有没有手写render方法 ,然后判断有没有用到template,如果有template就会做一些处理。如果template是一个dom对象的话就会拿到innerHTML的内容,否则就会警告没有定义这个template。
mount
$mount
./runtime/index
vm.$mount(vm.$options.el)
el
element
querySelector
options
render
template
dom
innerHTML
如果没有定义template,就会调用getOuterHTML方法 这个方法拿到dom对象的outerHTML,直接返回,如果没有就在外面包一层div再返回,实际上是outerHTML的polyfill的调用。这样就拿到了返回的dom字符串。 最后就是编译,调用compileToFunctions拿到生成的render函数以及静态render函数staticRenderFns。 最终Vue只认render函数,如果没有render函数,就转换成编译的模版。如果有render函数,就直接返回mount方法的调用 然后在index.js中执行mountComponent方法, 首先用vm.$el缓存el的值,然后判断有没有render函数,没有render函数就创建一个空的vnode,如果有template但是template不是以#开头就会报警告(用的runtime only版本,但是没有写render函数) 然后定义了一个updateComponent,这个其实是一个与Vue性能埋点有关的函数 最终调用了vm._update(vm._render(), hydrating),第一个参数是通过vm._render渲染出一个vnode
getOuterHTML
compileToFunctions
staticRenderFns
mountComponent
vm.$el
vnode
#
runtime only
updateComponent
vm._update(vm._render(), hydrating)
vm._render
接下来调用了new Watcher这是一个渲染Watcher,执行Watcher的构造,关键是判断expOrmFn是不是一个函数,如果是一个函数就会给getter赋值这个函数,否则调用parsePath方法把它转化成getter,之后调用了this.get()方法,关于依赖收集的, 在里面执行了getter方法,那实际上就是执行了updateComponent方法,那么就会执行vm._update以及vm._render,这两个函数就是最总我们要挂载在dom要用到的函数, 首先vm._render会渲染出一个vnode,然后vm._update就会传入vnode在生命周期中执行后续操作。
new Watcher
Watcher
expOrmFn
getter
parsePath
this.get()
vm._update