<div id="testdata">
<h1>{{msg}}</h1>
<p>{{name}}</p>
</div>
var app = new Vue({
data() {
return {
msg: 'hello,weekend!',
name: 'YanHSama'
}
},
mounted() {
console.log('vue', this);
},
watch: {
},
computed: {
},
methods: {
},
})
// mount
app.$mount('#testdata')
Vue.prototype.$mount
定义
找到入口src\platforms\web\entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount
缓存$mount
return mount.call(this, el, hydrating)
执行的是缓存的$mount
//src\platforms\web\entry-runtime-with-compiler.js
import Vue from './runtime/index'
//缓存的$mount,来自import Vue from './runtime/index'
const mount = Vue.prototype.$mount
//重新定义的$mount
Vue.prototype.$mount = function (el ?: string | Element, hydrating ?: boolean): Component {
// 获取el属性,挂载点
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
}
// options配置项
const options = this.$options
// 如果用户提供了 render 配置项,则直接跳过编译阶段,否则进入编译阶段, 优先级render——> template ——>el
if (!options.render) {
// console.log('inside', this)
let template = options.template
if (template) {
// 处理 template 选项
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
// { template: '#app' },template 是一个 id 选择器,则获取该元素的 innerHtml 作为模版
template = idToTemplate(template)
}
} else if (template.nodeType) {
// template 是一个正常的元素,获取其 innerHtml 作为模版
console.log('template.innerHTML', template.innerHTML)
template = template.innerHTML
} else {
return this
}
} else if (el) {
// 设置了 el 选项,获取 el 选择器的 outerHtml 作为模版
template = getOuterHTML(el)
}
if (template) {
// 编译模版,得到 动态渲染函数和静态渲染函数
const {
render,
staticRenderFns
} = compileToFunctions(template, {
shouldDecodeNewlines,
// 界定符,默认 {{}}
delimiters: options.delimiters,
// 是否保留注释
comments: options.comments
}, this)
// 将两个渲染函数放到 this.$options 上
options.render = render
options.staticRenderFns = staticRenderFns
}
}
// 执行挂载,执行的是缓存的$mount
return mount.call(this, el, hydrating)
}
/**
* Get outerHTML of elements, taking care
* of SVG elements in IE as well.
*/
function getOuterHTML (el: Element): string {
if (el.outerHTML) {
return el.outerHTML
} else {
const container = document.createElement('div')
container.appendChild(el.cloneNode(true))
return container.innerHTML
}
}
//src\platforms\web\runtime\index.js
import { mountComponent } from 'core/instance/lifecycle'
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
export function query (el: string | Element): Element {
if (typeof el === 'string') {
const selected = document.querySelector(el)
if (!selected) {
process.env.NODE_ENV !== 'production' && warn(
'Cannot find element: ' + el
)
return document.createElement('div')
}
return selected
} else {
return el
}
}
mountComponent函数
mountComponent
函数
//src\core\instance\lifecycle.js
export function mountComponent (vm: Component, el: ? Element, hydrating ?: boolean): Component {
vm.$el = el
// 当options没有render选项时,创建render
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode
if (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
)
}
}
}
// 执行beforeMount钩子
callHook(vm, 'beforeMount')
let updateComponent
// 非生产环境-性能相关埋点,可忽略
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = () => {
const name = vm._name
const id = vm._uid
const 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函数
updateComponent = () => {
// 负责调用vm._update: ( arg1:VNode , arg2:SSR相关 ) => {}
vm._update(vm._render(), hydrating)
}
}
// 设置_watcher,将updateComponent放入一个新建的渲染watcher实例
vm._watcher = new Watcher(vm, updateComponent, noop)
hydrating = false
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
// 在vm实例上标记了_isMounted为true
vm._isMounted = true
// 执行定义的生命周期钩子函数mounted
callHook(vm, 'mounted')
}
return vm
}
执行挂载完成