Vue源码解析之Template转化为AST的实现方法

Vue源码解析之Template转化为AST的实现方法

在Vue的编译过程中,将模板字符串转换为AST(抽象语法树)是至关重要的一步。本文将介绍Vue源码中关于Template转化为AST的实现方法。

Template转化为AST的流程

Vue中的模板转化为AST的流程主要包括以下几个步骤:

  1. 解析(parse)模板字符串,生成token数组
  2. 将token数组转化为AST

解析模板字符串

解析模板字符串的过程,核心是正则表达式,主要是针对html标签的匹配。具体实现方法可以看下面的代码示例:

function parseHTML(html, options) {

  while (html) {
    let textEnd = html.indexOf('<')
    if (textEnd === 0) {
      const endTag = html.match(endTagRE)
      if (endTag) {
        advance(endTag[0].length)
        continue
      }
    }

    let text, rest, next
    if (textEnd >= 0) {
      rest = html.slice(textEnd)
      while (
        !endTagRE.test(rest) &&
        !startTagOpenRE.test(rest) &&
        !commentRE.test(rest)
      ) {
        next = rest.indexOf('<', 1)
        if (next < 0) break
        textEnd += next
        rest = html.slice(textEnd)
      }
      text = html.substring(0, textEnd)
    }

      // ...more parsing code

  }
}

parseHTML函数输入的参数,就是我们要转化为AST的模板字符串,这里的实现方法中,首先判断字符串是否以"\<"开始,如果不是则认为是普通文本,直接截取并保存下来;如果是则表示匹配到了标签,这时候我们会进一步判断是否是结束标签,如果是的话则直接跳过;否则就是正常的开始标签,我们会进行标签解析。

将token数组转化为AST

经过第一步处理后,我们得到了一个token数组,接下来就可以通过此数组构建AST了。Vue的AST是通过使用 acorn 实现的,这是一个轻量级的 JavaScript 解析器,可以把JavaScript代码转化为抽象语法树(AST)。

Vue的AST结构和一般的AST结构有点不同,因为它包含了许多模板语法相关的节点,如v-if、v-for、v-on等等特殊节点。下面是一个AST的示例:

  {
    type: 1, // AST节点的类型,标签类型为1
    tag: 'div',    // 标签名称
    plain: true,   // 普通标签,非组件标签
    static: false, // 是否为静态节点
    ...
    children: [
      // 子节点为数组
      {
        type: 2, // AST节点的类型,属性类型为2
        name: 'v-if', // 属性名称
        value: 'isShow' // 属性值
      },
      {
        type: 3, // AST节点类型,文本节点类型为3
        text: 'hello world' // 文本节点的文本内容
      }
    ]
  }

示例演示

下面是一个简单的模板字符串,我们将会对其进行解析,得到AST:

<div>
  <h1 v-if="isShow">{{ title }}</h1>
  <p class="desc" v-for="(item, index) in list" :key="item.id" @click="handleClick">{{ item.name }}</p>
</div>

将上述模板字符串传入parseHTML函数进行解析,得到token数组:

[
  { type: 3, text: '\n  ' },
  { type: 1, tag: 'div', attrsList: [], attrsMap: {}, start: 0, end: 5, unarySlash: false, children: [] },
  { type: 3, text: '\n  ' },
  { type: 1,
    tag: 'h1',
    attrsList: [{ name: 'v-if', value: 'isShow' }],
    attrsMap: { v-if: 'isShow' },
    start: 7,
    end: 29,
    unarySlash: false,
    children: [ { type: 2, name: 'title', value: '_s(title)', dynamic: true, start: 20, end: 26, loc: [Object] } ] 
  },
  { type: 3, text: '\n  ' },
  { type: 1,
    tag: 'p',
    attrsList: 
     [ { name: 'class', value: 'desc' },
       { name: 'v-for', value: '(item, index) in list' },
       { name: ':key', value: 'item.id' },
       { name: '@click', value: 'handleClick' } ],
    attrsMap: 
     { class: 'desc',
       'v-for': '(item, index) in list',
       ':key': 'item.id',
       '@click': 'handleClick' },
    start: 31,
    end: 89,
    unarySlash: false,
    children: [ { type: 3, text: ' {{ item.name }}' } ] 
  },
  { type: 3, text: '\n' } 
]

将上述token数组传入parse函数中,得到AST:

{
  type: 1,
  tag: 'div',
  attrsList: [],
  attrsMap: {},
  rawAttrsMap: {},
  parent: undefined,
  children: [
    {
      type: 3,
      text: '\n  '
    },
    {
      type: 1,
      tag: 'h1',
      attrsList: [
        {
          name: 'v-if',
          value: 'isShow'
        }
      ],
      attrsMap: {
        'v-if': 'isShow'
      },
      rawAttrsMap: {},
      parent: [Circular],
      children: [
        {
          type: 2,
          expression: '_s(title)',
          tokens: [
            {
              '@binding': 'title'
            }
          ],
          text: '{{ title }}'
        }
      ],
      plain: false,
      static: false,
      staticRoot: false,
      hasBindings: true,
      key: undefined,
      scopedSlots: {},
      slotTarget: undefined,
      slotTargetDynamic: undefined,
      slotScope: undefined,
      attrs: []
    },
    {
      type: 3,
      text: '\n  '
    },
    {
      type: 1,
      tag: 'p',
      attrsList: [
        {
          name: 'class',
          value: 'desc'
        },
        {
          name: 'v-for',
          value: '(item, index) in list'
        },
        {
          name: ':key',
          value: 'item.id'
        },
        {
          name: '@click',
          value: 'handleClick'
        }
      ],
      attrsMap: {
        'class': 'desc',
        'v-for': '(item, index) in list',
        ':key': 'item.id',
        '@click': 'handleClick'
      },
      rawAttrsMap: {},
      parent: [Circular],
      children: [
        {
          type: 3,
          text: ' {{ item.name }}'
        }
      ],
      plain: false,
      static: false,
      staticRoot: false,
      hasBindings: true,
      key: undefined,
      scopedSlots: {},
      slotTarget: undefined,
      slotTargetDynamic: undefined,
      slotScope: undefined,
      attrs: [],
      computedName: undefined
    },
    {
      type: 3,
      text: '\n'
    }
  ],
  plain: false,
  static: false,
  staticRoot: false,
  hasBindings: false,
  key: undefined,
  scopedSlots: {},
  slotTarget: undefined,
  slotTargetDynamic: undefined,
  slotScope: undefined,
  attrs: []
}

以上就是Vue源码解析之Template转化为AST的实现方法的详细说明,其中包含了针对模板字符串的解析方法和将token转化为具有AST结构的方法,我们通过示例演示模板字符串的解析和AST的转化过程,希望对大家有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue源码解析之Template转化为AST的实现方法 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • vue 优化CDN加速的方法示例

    下面是详细讲解“vue 优化CDN加速的方法示例”的完整攻略。 一、什么是CDN加速 CDN (Content Delivery Network) 即内容分发网络,是指把内容发布到离最终用户最近的网络节点上,使用户可以就近取得所需内容。简单来说,CDN加速就是把静态资源放到离用户最近的服务器上,使用户能够更快地访问网站。 二、CDN加速的优点 CDN加速有如…

    Vue 2023年5月29日
    00
  • 详解如何使用router-link对象方式传递参数?

    使用router-link对象方式传递参数需要注意以下几点: 参数应该以对象的形式包含在to属性中; 在参数对象中使用query属性传递参数; 在目标路由组件中通过this.$route.query属性来获取传递过来的参数。 下面通过两个示例来具体说明如何使用router-link对象方式传递参数。 第一个示例:传递一个字符串参数 假设我们有两个路由组件,“…

    Vue 2023年5月27日
    00
  • 使用 Vue cli 3.0 构建自定义组件库的方法

    使用 Vue cli 3.0 构建自定义组件库的方法可以通过以下步骤实现: 1. 创建一个新的 Vue 项目 使用 Vue cli 3.0 创建一个新项目: vue create my-library 2. 配置组件库 在 “src” 目录下创建一个 “components” 目录,所有组件都将存放在这个目录中。为了确保组件可以在其他项目中使用,我们需要将这…

    Vue 2023年5月28日
    00
  • vue如何给数组添加新对象并赋值

    首先,我们需要明确需要添加的对象的数据结构,例如: { "id": 1, "name": "John Doe", "email": "johndoe@example.com" } 接着,我们可以使用Vue提供的响应式方法来添加一个对象到数组中: this.us…

    Vue 2023年5月28日
    00
  • 如何使用vue开发公众号网页

    下面我将详细讲解如何使用Vue开发公众号网页的完整攻略。 步骤一:创建Vue项目 首先,我们需要使用Vue CLI工具来创建一个新的Vue项目。Vue CLI是一个标准的脚手架工具,能够帮助我们快速创建Vue应用。 安装Vue CLI: npm install -g @vue/cli 创建一个新的Vue项目: vue create my-app 步骤二:安装…

    Vue 2023年5月28日
    00
  • vue自定义指令实现方法详解

    你要了解关于“vue自定义指令实现方法”的详细攻略,下面为你详细讲解。 什么是Vue自定义指令? 在Vue中,自定义指令是一种用来扩展标准的HTML指令的一种方式。除了内置的$v-cloak指令,Vue还允许注册自定义指令,使开发者可以在模板中直接使用自定义的指令。 Vue自定义指令的注册 定义一个全局自定义指令的方式: Vue.directive(‘my-…

    Vue 2023年5月27日
    00
  • Vue的watch和computed方法的使用及区别介绍

    Vue中的watch和computed都是用来监听数据变化的方法,但在使用时有些差别。下面将对Vue的watch和computed进行详细讲解,并给出两个示例。 Watch Watch的用法 watch可以监听数据的变化,并进行相应的操作。它可以监听一个或多个数据的变化,当数据发生变化时,会执行相应的回调函数。 watch: { username(newVa…

    Vue 2023年5月28日
    00
  • vue实现简单跑马灯效果

    接下来我将详细讲解如何使用Vue.js来实现简单跑马灯效果。 简介 跑马灯效果是一种常见的网页动效,指在页面上呈现一段文字或图片等内容循环滚动的效果。Vue.js是一款流行的JavaScript框架,提供了许多方便的工具和API,用于处理前端视图的更新和渲染。结合Vue.js的数据绑定和渲染功能,可以很容易地实现跑马灯的效果。 实现步骤 下面是实现跑马灯效果…

    Vue 2023年5月29日
    00
合作推广
合作推广
分享本页
返回顶部