vue模板编译流程

vue模板渲染过程主要分为三布

  1. parse 函数解析 template
  2. optimize 函数优化静态内容
  3. generate 函数创建 render 函数字符串

1. parse 解析

什么是AST?

AST 的全称是 Abstract Syntax Tree,也就是所谓抽象语法树,用来表示代码的数据结构。

在Vue中可以理解为嵌套的、携带标签名、属性和父子关系的JS对象,以树来表现DOM结构

// vue中的AST有三种类型

declare type ASTElement = {
    type: 1;
    tag: string;
    attrsList:Arraray<{name:string; value:string}>;
    attrsMap:{[key: string]: string|null};
    parent: ASTElement|void;
    children: Array<ASTNode>;
    // ....
}

declare type ASTExpression = {
    type: 2;
    expression: string;
    text: string:
    static?:boolean;
}
declare type ASTText = {
    type: 3;
    text: string;
    static?: boolean;
}

parse 函数里定义了许多的正则表达式,通过对标签名开头、标签名结尾、属性字段、文本内容等等的递归匹配。把字符串类型的 template 转化成了树状结构的 AST

<div id="test">texttext</div>

经过parse函数解析为

ele1 = {
  type: 1,
  tag: "div",
  attrsList: [{name: "id", value: "test"}],
  attrsMap: {id: "test"},
  parent: undefined,
  children: [{
      type: 3,
      text: 'texttext'
    }
  ],
  plain: true,
  attrs: [{name: "id", value: "'test'"}]
}

2. optimize 优化

optimize 优化会对 parse 生成的 AST 进行静态内容(和数据没有关系,不需要每次都刷新的内容)的优化,标记静态节点的作用是为了在后面做 Vnode 的 diff 时起作用。optimize 的过程分为两步:

  1. 标记所有的静态和非静态结点
  2. 标记静态根节点
// 源码
function markStatic (node: ASTNode) {
  // 标记 static 属性
  node.static = isStatic(node)
  if (node.type === 1) {
    // 注意这个判断逻辑
    if (
      !isPlatformReservedTag(node.tag) &&
      node.tag !== 'slot' &&
      node.attrsMap['inline-template'] == null
    ) {
      return
    }
    for (let i = 0, l = node.children.length; i < l; i++) {
      const child = node.children[i]
      markStatic(child)
      if (!child.static) {
        node.static = false
      }
    }
  }
}

isStatic 函数顾名思义是判断该节点是否 static 的函数,符合如下内容的节点就会被认为是 static 的节点

  1. 如果是表达式AST节点,直接返回 false
  2. 如果是文本AST节点,直接返回 true
  3. 如果元素是元素节点,阶段有 v-pre 指令 || (没有任何指令、数据绑定、事件绑定等 &&没有 v-if 和 v-for &&不是 slot 和 component &&是 HTML 保留标签 &&不是 template 标签的直接子元素并且没有包含在 for 循环中)则返回 true

3. generate 生成 render

几种内部方法
_c:对应的是 createElement 方法,顾名思义,它的含义是创建一个元素(Vnode)
_v:创建一个文本结点。
_s:把一个值转换为字符串。(eg: {{data}})
_m:渲染静态内容

// 例: 
<template>
  <div id="test">
    {{val}}
    <img src="http://xx.jpg">
  </div>
</template>
// 最终会被转换成这样子的函数字符串
{render: "with(this){return _c('div',{attrs:{"id":"test"}},[[_v(_s(val))]),_v(" "),_m(0)])}"}

results for ""

    No results matching ""