Wang's blog Wang's blog
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Wang Mings

跟随大神,成为大神!
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Python爬虫

  • 前端教程

    • 团队规范

    • Project

    • JS

    • NodeJS

    • Vue

      • 个人理解Vue和React区别
      • Vue高级用法
      • Vue2.x源码分析 - 框架结构
      • Vue2.x源码分析 - 模版编译以及挂载
      • 虚拟dom算法库 - snabbdom
      • Vue2.x源码分析 - Virtual DOM实现
      • Vue2.x源码分析 - 事件系统
      • Vue2.x源码分析 - 组件系统
      • Vue2.x源码分析 - Vue.nextTick
      • Vue2.x源码分析 - inject provide
      • Vue2.x源码分析 - 解析Template模板
        • [#](#整体流程) 整体流程
        • [#](#ast-tree) AST Tree
      • Vue2.x源码分析 - 响应式原理
      • Vue2.x源码分析 - v-model
      • Vue CLI3 插件系统原理
      • Vue Loader v15 源码解析
      • Vue3 设计思想
      • Vue3 RFCS导读
      • Vue3 响应式原理 - Ref Reactive Effect源码分析
      • Vue3 API 源码解析
      • 为何Vue3 Proxy 更快
      • Vue核心原理 - 笔记
    • React

    • 效率工具

    • 读书笔记

  • 教程
  • 前端教程
  • Vue
wangmings
2022-07-19
目录

Vue2.x源码分析 - 解析Template模板

# # Vue2.x源码分析 - 解析Template模板

编译过程首先就是对模板做解析,生成 AST,它是一种抽象语法树,是对源代码的抽象语法结构的树状表现形式。

Vue的实现方式是从头开始解析,运用正则表达式查找,逐部分字符分析、处理、删减,直到处理完整个template字符,最终得到一颗完整的AST Tree。代码在src/compiler/parser/index.js中的parseHTML()。

# # 整体流程

  1. 遇到注释/doctype时,游标跳过整段。

  2. 遇到开始标签<

    1. 解析tag标签,拿到startTagMatch
    2. 读取tag标签, 如'<h1',游标向前'<tag'
    3. 读取标签上属性。游标向前移动'所有属性'
    • /^\s*([^\s"'<>/=]+)(?:\s*(=)\s*(?:"([^"])"+|'([^'])'+|([^\s"'=<>`]+)))?/
    1. 读取tag标签的右尖括号'>',游标向前加1
    • /^\s*(/?)>/ image
    1. 处理tag和属性(执行option.start),管理ASTElement。(创建 AST 元素,处理 AST 元素,AST 树管理(比如维护父子关系,这时候就用到stack栈)。)
        if (inVPre) {
            processRawAttrs(element)
        } else if (!element.processed) {
            // structural directives
            processFor(element)
            processIf(element)
            processOnce(element)
            processElement(element, options) // processKey/processRef/processSlot/processComponent/processAttrs
        }
        
1
2
3
4
5
6
7
8
9
10
3.  使用stack压入tag标签,通过这个栈可得知标签的父子关系 ![image](/assets/images-1/44.png)
  1. 遇到纯文本,解析,游标往前移动。执行options.chars
  2. 遇到结束标签</>
    • 执行option.end,游标向前移动
    export function parseHTML (html, options) {
      let lastTag
      while (html) {
        if (!lastTag || !isPlainTextElement(lastTag)){
          let textEnd = html.indexOf('<')
          // 如果是<开头
          if (textEnd === 0) {
              // 注释/Doctype都是匹配整个区域
             if(matchComment) {
               advance(commentLength)
               continue
             }
             if(matchDoctype) {
               advance(doctypeLength)
               continue
             }
             // 匹配结尾,如</h1>。new RegExp(`^<\\/${qnameCapture}[^>]*>`)
             if(matchEndTag) {
               advance(endTagLength)
               parseEndTag() // 1. stack弹出标签 2. options.end
               continue
             }
             // 匹配开始
             if(matchStartTag) {
               parseStartTag() // 将<h1 name="123">分别处理为:<h1、name="123"、>
               handleStartTag() // stack压入 2. options.start
               continue
             }
          }
          // 开闭标签之间的纯文本
          handleText()
          advance(textLength)
        } else {
           // 处理特殊的script,style,textarea
           handlePlainTextElement()
           parseEndTag()
        }
      }
    }
    
    function advance (n) {
      index += n
      html = html.substring(n) // 每次都截取文字
    }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    // 处理时html在变化(游标作用)
    " v-for="branch in branches">
            <input type="radio" :id="branch" :value="branch" name="branch" v-model="currentBranch">
            <label :for="branch">{{ branch }}</label>
          </template>
          <p>vuejs/vue@{{ currentBranch }}</p>
        </div>"
    
1
2
3
4
5
6
7
8

# # AST Tree

    <ul :class="bindCls" class="list" v-if="isShow">
        <li v-for="(item,index) in data" @click="clickItem(index)">{{item}}:{{index}}</li>
    </ul>
    
1
2
3
4
    ast = {
      'type': 1,
      'tag': 'ul',
      'attrsList': [],
      'attrsMap': {
        ':class': 'bindCls',
        'class': 'list',
        'v-if': 'isShow'
      },
      'if': 'isShow',
      'ifConditions': [{
        'exp': 'isShow',
        'block': // ul ast element
      }],
      'parent': undefined,
      'plain': false,
      'staticClass': 'list',
      'classBinding': 'bindCls',
      'children': [{
        'type': 1,
        'tag': 'li',
        'attrsList': [{
          'name': '@click',
          'value': 'clickItem(index)'
        }],
        'attrsMap': {
          '@click': 'clickItem(index)',
          'v-for': '(item,index) in data'
         },
        'parent': // ul ast element
        'plain': false,
        'events': {
          'click': {
            'value': 'clickItem(index)'
          }
        },
        'hasBindings': true,
        'for': 'data',
        'alias': 'item',
        'iterator1': 'index',
        'children': [
          'type': 2,
          'expression': '_s(item)+":"+_s(index)'
          'text': '{{item}}:{{index}}',
          'tokens': [
            {'@binding':'item'},
            ':',
            {'@binding':'index'}
          ]
        ]
      }]
    }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
编辑 (opens new window)
Vue2.x源码分析 - inject provide
Vue2.x源码分析 - 响应式原理

← Vue2.x源码分析 - inject provide Vue2.x源码分析 - 响应式原理→

最近更新
01
theme-vdoing-blog博客静态编译问题
09-16
02
搜索引擎
07-19
03
友情链接
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式