vue3的模版解析过程

73 阅读2分钟

一、编译阶段

注意:编译阶段在组件实例化过程完成——实例化即为当一个 Vue 组件被使用时,Vue 会根据组件的定义创建一个组件实例

1.解析模版,

模板通过解析器转换成抽象语法树(AST, Abstract Syntax Tree),即AST, Abstract Syntax Tree,即Vue 会将模板中的 HTML 结构、指令(如 v-ifv-for)、事件绑定等都转换成一个树状结构

<div v-if="isVisible">
  <p>{{ message }}</p>
</div>

会把以上模版转化为以下AST语法树

{
  type: 'element',
  tag: 'div',
  props: [{ name: 'v-if', value: 'isVisible' }],
  children: [
    {
      type: 'element',
      tag: 'p',
      children: [
        {
          type: 'text',
          content: '{{ message }}'
        }
      ]
    }
  ]
}

2.优化阶段

模板初步解析为AST语法树之后,还要进行一个小优化阶段,会把静态节点(静态html元素,静态类名和样式等)标记,并且静态提升这些被标记的静态内容,避免更新时重复编译。静态提升即为Vue 会把静态节点提升到父组件的 render 函数外,避免每次重新渲染时重新计算这些静态内容

3.生成渲染函数(Render)

编译阶段的最后,Vue 会将 AST 转换为渲染函数。这些渲染函数会返回虚拟 DOM,这些虚拟 DOM 作为 JavaScript 对象存在,不直接操作实际 DOM
会把上述的AST转化为如下的渲染函数

function render() {
  return this.isVisible ? h('div', [   //`h` 是 Vue 内部用于创建虚拟 DOM 的函数,等同于 `createElement`
    h('p', this.message)
  ]) : null;
}

注意:渲染函数产生的是虚拟DOM,作为JavaScrip对象存在
如果是v-for的话,渲染函数如下

function render(){
const listItems = items.map(item => (
  h('li', { key: item.id }, item.name)
));
return h('ul', listItems);
}

可以看出,最终转化的render函数和react中的JSX有些类似,但也有差异,需要利用类似createElement方法创建虚拟DOM节点

二、运行阶段

执行渲染函数和更新

在组件挂载之前(即进入onMounted周期之前),通过render渲染函数已经返回的虚拟dom树生成真实dom树, 数据更新后,重新进行模块的编译,返回新的render函数(虚拟dom树),再进行diff算法更新真实dom树