讲解“每天学点Vue源码之vm.$mount挂载函数”的完整攻略。
什么是vm.$mount挂载函数?
vm.$mount
是 Vue 实例的 $mount()
函数,用于把Vue实例挂载到页面中的元素上。该函数有两种使用方式:
1.手动挂载
在手动挂载时,可以通过引入 Vue.js,创建 Vue 实例并手动挂载到一个DOM上。具体代码如下:
<!-- 在DOM中定义一个空白的DIV元素 -->
<div id="app"></div>
<!-- 引入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
// 创建Vue实例
var vm = new Vue({
el: '#app', // 指定挂载元素
data: {
message: 'Hello Vue!'
}
})
</script>
2.运行时编译挂载
在运行时编译时,可以通过使用 webpack 或者 vue-loader 等构建工具对 Vue 代码进行编译,自动挂载到相应的DOM元素上。该方式需要在 Vue 中进行配置。具体代码如下:
<!-- 在DOM中定义一个空白的DIV元素 -->
<div id="app"></div>
<!-- 引入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
// 创建Vue实例
var vm = new Vue({
template: '<div>Hello {{name}}!</div>',
data: {
name: 'Vue'
}
})
// 运行时编译挂载
vm.$mount('#app')
</script>
$mount挂载函数的具体实现
在 Vue.js 的源码中,$mount
函数主要实现了以下几个过程:
- 初始化组件
首先会进行组件实例化的初始化,在使用 new Vue()
创建一个 Vue 实例时,会自动调用 _init()
来进行初始化。在 部分源码如下:
Vue.prototype._init = function (options) {
const vm = this
vm._uid = uid++ // 增加_uid属性,用于标识唯一的实例ID
let startTag, endTag // 定义起始标签和结束标签
// 如果启动生产模式,进行模板语法错误检查
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
startTag = `vue-perf-start:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}`
mark(startTag)
}
// 定义_isVue标记
vm._isVue = true
// Merge options
if (options && options._isComponent) { // 处理组件的逻辑
initInternalComponent(vm, options)
} else { // 处理普通Vue实例的逻辑
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
// ...
}
- 获取挂载点元素
接着,会获取到传递的参数,并以此获取到el
元素。如果 el
元素不存在,需要通过 template
或者手动在代码中创建一个新的 DOM 元素并挂载到身上来。具体源码如下:
Vue.prototype.$mount = function (el?: string | Element, hydrating?: boolean): Component {
// ...
// 获取挂载的DOM元素
const options = this.$options
if (!options.render) {
let template = options.template
if (template) { // 处理template属性
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template)
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) { // template是元素节点(不常用)
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) { // 如果没有template属性,就将el作为模板并获取内部HTML
template = getOuterHTML(el)
}
// 如果解析到了template模板,则进行编译
if (template) {
const { render, staticRenderFns } = compileToFunctions(
template,
{
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
},
this
)
options.render = render
options.staticRenderFns = staticRenderFns
}
}
// ...
}
- 进行组件挂载
最后一个关键步骤是进行组件挂载。具体过程中,会判断是否有渲染函数(render
),如果没有,则生成一个渲染函数并准备对渲染函数进行编译。如果有,就把渲染函数转换成可执行的 vdom。具体源码如下:
Vue.prototype.$mount = function (el?: string | Element, hydrating?: boolean): Component {
// ...
// 如果没有渲染函数,则生成一个渲染函数
if (!options.render) {
render = noop
// 对模板进行编译(这个需要单独介绍)
const template = options.template
if (template) {
// ...
} else if (el) {
// ...
}
}
// ...
// 挂载组件
const updateComponent = () => {
vm._update(vm._render(), hydrating)
}
// ...
}
两个 $mount 挂载函数的详细示例
下面给出两个 $mount 挂载函数的示例。
示例1:手动挂载Vue实例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo-example-1</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="example">{{ msg }}</div>
</body>
</html>
var app = new Vue({
el: '#example',
data: {
msg: 'Hello, Vue!'
}
})
在这个例子中,手动创建 Vue 实例 app
,并手动将其挂载到 DOM 元素 #example
上。msg
属性的初始值是 "Hello, Vue!"。
示例2:运行时编译挂载
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo-example-2</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const app = new Vue({
template: '<div>Hello {{ name }}!</div>',
data: {
name: 'Vue'
}
})
app.$mount('#app')
</script>
</html>
在这个例子中,运行时编译时,传入 template
属性并定义了对应的数据属性。在 $mount
方法执行时,会将传入的 template
编译成 render
函数并执行挂载。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:每天学点Vue源码之vm.$mount挂载函数 - Python技术站