vue渲染过程
①模版代码
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ message }}</p>
<button @click="handleClick">Click Me</button>
</div>
</template>
// 假设有一个根元素的容器
const app = new Vue({
render: render,
data: {
title: 'Hello Vue',
message: 'Welcome to Vue.js'
},
methods: {
handleClick() {
console.log('Button clicked');
}
}
}).$mount('#app');
假定模版代码如上所示,其中title值是Hello Vue,message 值是Welcome to Vue.js
②AST语法树
vue编译器将上面的模版代码转换为ast树,具体生成的实现和源码解读参考之前文章。
什么是ast?
AST(抽象语法树)是编译过程中生成的一种树状数据结构,它表示了代码的抽象结构。在 Vue 中,AST 主要用于解析和编译模板。AST的结构定义通常包含以下属性
type:表示节点的类型,如元素节点、文本节点、插值节点等。tag:表示元素节点的标签名。attrs:表示元素节点的属性列表。children:表示元素节点的子节点列表。expression:表示插值节点或指令节点的表达式。
{
"type": 1,
"tag": "template",
"children": [
{
"type": 1,
"tag": "div",
"children": [
{
"type": 1,
"tag": "h1",
"children": [
{
"type": 2,
"expression": "_s(title)",
"text": "{{ title }}"
}
]
},
{
"type": 1,
"tag": "p",
"children": [
{
"type": 2,
"expression": "_s(message)",
"text": "{{ message }}"
}
]
},
{
"type": 1,
"tag": "button",
"attrs": [
{
"name": "@click",
"value": "handleClick"
}
],
"children": [
{
"type": 3,
"text": "Click Me"
}
]
}
]
}
]
}
③render函数
vue会根据ast语法树,生成该模版代码的render函数。
render函数是通过遍历AST,根据每个节点的类型和属性,生成相应的渲染代码
function render() {
return _c(
'div',
{},
[
_c('h1', {}, [_v(_s(title))]),
_c('p', {}, [_v(_s(message))]),
_c('button', { on: { click: handleClick } }, [_v('Click Me')])
],
1 /* 告诉 Vue 这是根节点 */
);
}
其中 _c 是 Vue 提供的渲染函数,用于创建一个虚拟 DOM 节点;_v 是用于创建文本节点的渲染函数;_s 是用于将数据转换为字符串的渲染函数。
通过将节点类型、标签、属性、事件等信息转换为渲染函数的调用,最终生成了一个可以被 Vue 实例调用的 render 函数。
④虚拟dom
{
"tag": "div",
"children": [
{
"tag": "h1",
"children": [
{
"type": 3,
"text": "Hello Vue"
}
]
},
{
"tag": "p",
"children": [
{
"type": 3,
"text": "Welcome to Vue.js"
}
]
},
{
"tag": "button",
"events": {
"click": "handleClick"
},
"children": [
{
"type": 3,
"text": "Click Me"
}
]
}
]
}
虚拟dom和ast区别
通过上面的代码你会发现,虚拟dom和ast树好像很像,结构属性中也有一些重叠。但是实际的结构定义和作用还是有所区别的。
- AST的文本显示还是原有vue字符串,并没有替换为data声明的字符串;虚拟dom树则可以清晰看出
- AST是表示了模版代码的语法结构以及层级之前的关系和逻辑关联。虚拟dom更关注与最终渲染dom的一些属性和状态。
- AST是对模版的抽象表示,主要用于模版语法的编译和转换。虚拟dom是实际dom的虚拟表示,vue通过比较新旧虚拟dom的差异来确认哪些是需要更新的部分,从而提高性能。
⑤真实dom
<div>
<h1>Hello Vue</h1>
<p>Welcome to Vue.js</p>
<button>Click Me</button>
</div>