vue渲染过程

137 阅读2分钟

vue渲染过程

drawio

image.png

①模版代码

<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 Vuemessage 值是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树好像很像,结构属性中也有一些重叠。但是实际的结构定义和作用还是有所区别的。

  1. AST的文本显示还是原有vue字符串,并没有替换为data声明的字符串;虚拟dom树则可以清晰看出
  2. AST是表示了模版代码的语法结构以及层级之前的关系和逻辑关联。虚拟dom更关注与最终渲染dom的一些属性和状态。
  3. AST是对模版的抽象表示,主要用于模版语法的编译和转换。虚拟dom是实际dom的虚拟表示,vue通过比较新旧虚拟dom的差异来确认哪些是需要更新的部分,从而提高性能。

⑤真实dom

<div>
  <h1>Hello Vue</h1>
  <p>Welcome to Vue.js</p>
  <button>Click Me</button>
</div>