$mount 方法在由于跟构建方式相关,所以在很多地方都被定义,我们先来看在原型上定义的$mount。
目录:src/platform/web/runtime/index.js
Vue.prototype.$mount = function (el?: string | Element,hydrating?: boolean): Component {el = el && inBrowser ? query(el) : undefinedreturn mountComponent(this, el, hydrating)}
可以看到$mount方法接受两个参数,第一个参数是el,表示要挂载的元素,el可以使字符串或DOM对象,如果是字符串,则调用query方法转为DOM对象,第二个参数是和服务端渲染相关,在浏览器环境下我们不需要传第二个参数。
调用$mount方法实际会去调用mountComponent()方法
mountComponent()方法在src/core/instance/lifecycle.js中定义
export function mountComponent (vm: Component,el: ?Element,hydrating?: boolean): Component {vm.$el = elif (!vm.$options.render) {vm.$options.render = createEmptyVNodeif (process.env.NODE_ENV !== 'production') {/* istanbul ignore if */if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||vm.$options.el || el) {warn('You are using the runtime-only build of Vue where the template ' +'compiler is not available. Either pre-compile the templates into ' +'render functions, or use the compiler-included build.',vm)} else {warn('Failed to mount component: template or render function not defined.',vm)}}}callHook(vm, 'beforeMount')let updateComponent/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {updateComponent = () => {const name = vm._nameconst id = vm._uidconst startTag = `vue-perf-start:${id}`const endTag = `vue-perf-end:${id}`mark(startTag)const vnode = vm._render()mark(endTag)measure(`vue ${name} render`, startTag, endTag)mark(startTag)vm._update(vnode, hydrating)mark(endTag)measure(`vue ${name} patch`, startTag, endTag)}} else {updateComponent = () => {vm._update(vm._render(), hydrating)}}// we set this to vm._watcher inside the watcher's constructor// since the watcher's initial patch may call $forceUpdate (e.g. inside child// component's mounted hook), which relies on vm._watcher being already definednew Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted && !vm._isDestroyed) {callHook(vm, 'beforeUpdate')}}}, true /* isRenderWatcher */)hydrating = false// manually mounted instance, call mounted on self// mounted is called for render-created child components in its inserted hookif (vm.$vnode == null) {vm._isMounted = truecallHook(vm, 'mounted')}return vm}
上面代码可以看到mountComponent()的核心就是先实例化一个Wancher,然后在回调中调用updateComponent,在updateComponent中调用vm.render方法生成虚拟Node最终调用vm._update更新DOM。
Watcher在这里起两个作用,一个是初始化的时候会执行回调函数,触发执行vm._render和vm._updata,另一个是当vm实例中监测的数据发生变化是执行回调函数(后面介绍)。
函数最后判断为根节点的时候设置 vm._isMounted 为 true, 表示这个实例已经挂载了,同时执行 mounted 钩子函数。 这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例
