从 new Vue 到所有组件 mounted 的全过程
2024-01-11 07:56:27
从 new Vue 到所有组件 mounted 的全过程
从 new Vue({ render: h => h(App) }).mount('#app') 到页面上出现对应的 DOM 内容,这中间的过程是如何发生的?主要分为以下几小结:
- Vue 以及由它创建的 vm 实例的属性是如何来的
- vnode 和 vm 实例的 props 数据是如何绑定的
- 如何根据 vnode 创建真实 DOM 的
- 如何进行 diff 算法的比较
- 如何更新 DOM 的
- Vue.nextTick 是如何工作的
Vue 以及由它创建的 vm 实例的属性是如何来的
Vue 实例的属性
Vue 实例的属性分为两类:一是 data 选项中声明的属性,二是计算属性。
- data 选项中声明的属性
data 选项中声明的属性是 Vue 实例最基本的数据属性,它们直接存储在 Vue 实例的 _data
属性中。
const vm = new Vue({
data: {
name: 'John',
age: 20
}
})
console.log(vm._data) // { name: 'John', age: 20 }
- 计算属性
计算属性是 Vue 实例中另一种常见的数据属性。计算属性的值不是直接存储在 Vue 实例的 _data
属性中,而是通过一个 getter 函数计算得到。
const vm = new Vue({
data: {
name: 'John',
age: 20
},
computed: {
fullName() {
return this.name + ' ' + this.age
}
}
})
console.log(vm.fullName) // 'John 20'
vm 实例的其他属性
除了 data 选项中声明的属性和计算属性外,vm 实例还有许多其他属性,这些属性都是由 Vue 内部创建的,用于支持 Vue 实例的各种功能。
例如,vm 实例有一个 $el
属性,指向挂载 Vue 实例的 DOM 元素。vm 实例还有一个 $refs
属性,包含了所有使用 ref 属性的子组件的引用。
const vm = new Vue({
el: '#app',
data: {
name: 'John',
age: 20
},
template: `
<div>
<p>{{ name }}</p>
<p>{{ age }}</p>
</div>
`
})
console.log(vm.$el) // <div id="app">...</div>
console.log(vm.$refs) // { child: { name: 'John', age: 20 } }
vnode 和 vm 实例的 props 数据是如何绑定的
vnode 是 Vue 中虚拟 DOM 的最小单元,它代表了 DOM 树中的一个节点。vnode 有一个 props
属性,包含了该 vnode 对应的组件的 props 数据。
当 Vue 实例被创建时,它会根据 template
选项或 render
函数创建一个 vnode。然后,Vue 实例会将 vnode 的 props 数据绑定到组件的实例上。
const vm = new Vue({
data: {
name: 'John',
age: 20
},
template: `
<div>
<child-component :name="name" :age="age"></child-component>
</div>
`
})
console.log(vm.$children[0].$props) // { name: 'John', age: 20 }
如何根据 vnode 创建真实 DOM 的
当 Vue 实例被创建时,它会根据 vnode 创建一个真实的 DOM 元素。这个过程叫做 patching 。
Patching 过程是递归的,它从根 vnode 开始,然后逐层遍历 vnode 树,为每个 vnode 创建一个真实的 DOM 元素。
const vm = new Vue({
data: {
name: 'John',
age: 20
},
template: `
<div>
<p>{{ name }}</p>
<p>{{ age }}</p>
</div>
`
})
const rootNode = vm._vnode
const realDOM = patch(rootNode)
console.log(realDOM) // <div>...</div>
如何进行 diff 算法的比较
当 Vue 实例更新时,它会使用 diff 算法来比较新旧 vnode 的差异。diff 算法会找出新旧 vnode 之间的差异,并只更新那些发生变化的 DOM 元素。
Diff 算法是 Vue 性能优化非常重要的一部分。如果没有 diff 算法,Vue 就需要在每次更新时重新渲染整个组件树,这会极大地降低 Vue 的性能。
如何更新 DOM 的
当 diff 算法找出新旧 vnode 之间的差异后,Vue 实例就会更新 DOM。
Vue 实例会使用 patch
函数来更新 DOM。patch
函数会根据新旧 vnode 之间的差异,对 DOM 进行相应的更新。
const vm = new Vue({
data: {
name: 'John',
age: 20
},
template: `
<div>
<p>{{ name }}</p>
<p>{{ age }}</p>
</div>
`
})
vm.name = 'Mary'
patch(vm._vnode, vm._vnode)
Vue.nextTick 是如何工作的
Vue.nextTick 是 Vue 中一个非常重要的函数,它可以让我们在 Vue 实例更新完成之后执行某些操作。
Vue.nextTick 的工作原理是将一个回调函数推入到一个队列中,然后在下次 DOM 更新循环结束之后执行这个队列中的所有回调函数。
const vm = new Vue({
data: {
name: 'John',
age: 20
},
template: `
<div>
<p>{{ name }}</p>
<p>{{ age }}</p>
</div>
`
})
vm.name = 'Mary'
Vue.nextTick(() => {
console.log(vm.name) // 'Mary'
})