vue parseHTML函数源码解析 AST预备知识

目录
  • 正文
  • createASTElement函数
    • 解析指令所用正则
    • parse 函数中的变量

正文

接上章节:parseHTML 函数源码解析AST 基本形成

在正式扎进Vue parse源码之前,我们先了解下他周边的工具函数, 这能帮我们快速的去理解阅读。

还记得我们在上章节讲的element元素节点的描述对象吗?

var element = {
	type: 1,
	tag: tag,
	parent: null,
	attrsList: attrs,
	children: []
}

在源码中定义了一个createASTElement函数,用来创建一个元素的描述对象。

createASTElement函数

function createASTElement(tag, attrs, parent) {
		return {
			type: 1,
			tag: tag,
			attrsList: attrs,
			attrsMap: makeAttrsMap(attrs),
			parent: parent,
			children: []
		}
	}

解析指令所用正则

var onRE = /^@|^v-on:/;
var dirRE = /^v-|^@|^:/;
var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
var stripParensRE = /^\(|\)$/g;
var argRE = /:(.*)$/;
var bindRE = /^:|^v-bind:/;
var modifierRE = /\.[^.]+/g;

在解析开始标签的时候你遇到的不仅有属性,还有一些Vue 自定义的指令。下面一起来分析下解析指令会有用哪些正则。

onRE

var onRE = /^@|^v-on:/;

匹配以字符 @ 或 v-on: 开头的字符串,主要作用是检测标签属性名是否是监听事件的指令。

dirRE

var const dirRE = /^v-|^@|^:/

匹配以字符 v- 或 @ 或 : 开头的字符串,主要作用是检测标签属性名是否是指令。在Vue中所有以 v- 开头的属性都被认为是指令,另外@字符是 v-on 的缩写,: 字符是 v-bind 的缩写。

forAliasRE

var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;

匹配 v-for 属性的值,并捕获 in 或 of 前后的字符串。都是正则大神就不解释怎么捕获的了。

forIteratorRE

var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;

这个也是匹配v-for的属性值,不过比之前要稍微复杂点:列表渲染 v-for(https://cn.vuejs.org/v2/guide/list.html)需要先了解下这个。

//示例:1
<div v-for="(value, name) in object">
  {{ name }}: {{ value }}
</div>
//示例:2
<div v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</div>

没错就是用来捕获,示例1中的:'obj , index' 示例2中的:'value, key, index' 。

stripParensRE

var stripParensRE = /^\(|\)$/g;

这个捕获组用来捕获要么以字符 ( 开头,要么以字符 ) 结尾的字符串,或者两者都满足。那么这个正则的作用是什么呢?我们在讲解正则 forIteratorRE 时有个细节不知道大家注意到了没有,就是 forIteratorRE 正则所匹配的字符串是 'obj, index' ,而不是 '(obj, index)' ,这两个字符串的区别就在于第二个字符串拥有左右括号,所以在使用 forIteratorRE 正则之前,需要使用 stripParensRE 正则去掉字符串 '(obj, index)' 中的左右括号,实现方式很简单:

"(obj, index)".replace(stripParensRE, "")

argRE

var argRE = /:(.*)$/;

argRE正则用来匹配指令编写中的参数,并且拥有一个捕获组,用来捕获参数的名字。

示例:

<div v-on:click.item="handle"></div>

其中 v-on 为指令,click为传递给 v-on 指令的参数,stop 为修饰符。

bindRE

var bindRE = /^:|^v-bind:/;

该正则用来匹配以字符:或字符串 v-bind: 开头的字符串,主要用来检测一个标签的属性是否是绑定(v-bind)。

modifierRE

var modifierRE = /\.[^.]+/g;

该正则用来匹配修饰符的,但是并没有捕获任何东西,但你可以用match、exec等方法获取与当前正则匹配成功的信息。

parse 函数中的变量

在讲解 parse 函数直接我们还需要先了解下它内部所定义的一些变量以及用途。

function parse(template, options) {
	warn$2 = options.warn || baseWarn;
	platformIsPreTag = options.isPreTag || no;
	platformMustUseProp = options.mustUseProp || no;
	platformGetTagNamespace = options.getTagNamespace || no;
	transforms = pluckModuleFunction(options.modules, 'transformNode');
	preTransforms = pluckModuleFunction(options.modules, 'preTransformNode');
	postTransforms = pluckModuleFunction(options.modules, 'postTransformNode');
	delimiters = options.delimiters;
	var stack = [];
	var preserveWhitespace = options.preserveWhitespace !== false;
	var root;
	var currentParent;
	var inVPre = false;
	var inPre = false;
	var warned = false;
	function warnOnce(msg) {
        //...
	}
	function closeElement(element) {
       //...
	}
	parseHTML(template, {
		warn: warn$2,
		expectHTML: options.expectHTML,
		isUnaryTag: options.isUnaryTag,
		canBeLeftOpenTag: options.canBeLeftOpenTag,
		shouldDecodeNewlines: options.shouldDecodeNewlines,
		shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
		shouldKeepComment: options.comments,
		start: function start(tag, attrs, unary) {},
		end: function end() {},
		chars: function chars(text) {},
		comment: function comment(text) {},
	});
	return root
}

我们先来看下针对web平台初始化的一些变量。

warn$2 = options.warn || baseWarn;
platformIsPreTag = options.isPreTag || no;
platformMustUseProp = options.mustUseProp || no;
platformGetTagNamespace = options.getTagNamespace || no;
transforms = pluckModuleFunction(options.modules, 'transformNode');
preTransforms = pluckModuleFunction(options.modules, 'preTransformNode');
postTransforms = pluckModuleFunction(options.modules, 'postTransformNode');
delimiters = options.delimiters;
  • warn$2 函数 毋庸置疑它作用是用来打印警告信息的
  • platformIsPreTag 函数是一个编译器选项,其作用是通过给定的标签名字判断该标签是否是 pre 标签。
  • platformMustUseProp 该函数也是一个编译器选项,其作用是用来检测一个属性在标签中是否要使用元素对象原生的 prop 进行绑定。
  • platformGetTagNamespace 该函数是一个编译器选项,其作用是用来获取元素(标签)的命名空间。
  • transforms 、preTransforms 、postTransforms 还没讲到它们的上下文,暂时不解释它们的作用。
  • delimiters 它的值为 options.delimiters 属性,它的值就是在创建 Vue 实例对象时所传递的 delimiters 选项。

继续往下看:

var stack = [];
var preserveWhitespace = options.preserveWhitespace !== false;
var root;
var currentParent;
var inVPre = false;
var inPre = false;
var warned = false;
  • stack 初始值是一个空数组,作用在上个章节我们讲到,回退操作为了让子元素描述对象的parent属性能够正确指向其父元素。
  • preserveWhitespace 是一个布尔值并且它的值与编译器选项中的options.preserveWhitespace选项有关,只要 options.preserveWhitespace 的值不为false,那么 preserveWhitespace 的值就为真。其中 options.preserveWhitespace 选项用来告诉编译器在编译 html 字符串时是否放弃标签之间的空格,如果为 true 则代表放弃。
  • root 存储最终生成的AST。
  • currentParent 通过上章节了解到,该变量维护元素描述对象之间的父子关系。
  • inVPre 初始值:false。标识当前解析的标签是否在拥有 v-pre (跳过这个元素和它的子元素的编译过程。)的标签之内。
  • inPre 初始值:false。标识当前正在解析的标签是否在 <pre></pre> 标签之内。
  • warned 初始值:false。用来打印警告信息的函数,只不过 warnOnce 函数就如它的名字一样,只会打印一次警告信息,并且 warnOnce 函数也是通过调用 warn 函数来实现的。

好了一些边边角角的东西就先讲到这,接下来我们一起来分析Vue parse源码看看一颗完整的AST树是如何构建出来的。更多关于vue parseHTML函数AST预备的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue parseHTML函数解析器遇到结束标签

    目录 引言 match函数匹配正则endTag 关键 parseEndTag 函数代码 总结parseEndTag 函数作用 handleStartTag函数后续 最后更新 stack 栈以及 lastTag 引言 承接上篇 parseHTML 函数源码解析拿到返回值后的处理 接下来我们将会讲解当 textEnd === 0 解析器遇到结束标签,parse 结束标签的代码如下: // End tag: var endTagMatch = html.match(endTag); if (endTa

  • vue parseHTML 函数源码解析

    目录 正文 函数开头定义的一些常量和变量 while 循环 textEnd ===0 parseStartTag 函数解析开始标签 总结: 正文 接上篇: Vue编译器源码分析AST 抽象语法树 function parseHTML(html, options) { var stack = []; var expectHTML = options.expectHTML; var isUnaryTag$$1 = options.isUnaryTag || no; var canBeLeftOpen

  • vue parseHTML源码解析hars end comment钩子函数

    目录 引言 chars源码: parseText end 源码: 引言 接上文  parseHTML 函数源码解析(六) start钩子函数 接下来我们主要讲解当解析器遇到一个文本节点时会如何为文本节点创建元素描述对象,又会如何对文本节点做哪些特殊的处理. parseHTML(template, { chars: function(){ //... }, //... }) chars源码: chars: function chars(text) { if (!currentParent) { {

  • vue parseHTML函数源码解析start钩子函数

    目录 正文 platformGetTagNamespace 源码 isForbiddenTag 函数 addIfCondition是什么 processIfConditions 源码 正文 接上章节:parseHTML 函数源码解析 AST 预备知识 现在我们就可以愉快的进入到Vue start钩子函数源码部分了. start: function start(tag, attrs, unary) { // check namespace. // inherit parent ns if ther

  • vue parseHTML 函数源码解析AST基本形成

    目录 AST(抽象语法树)? 子节点 Vue中是如何把html(template)字符串编译解析成AST 解析html 代码重新改造 接着解析 html (template)字符串 解析div AST(抽象语法树)? 在上篇文章中我们已经把整个词法分析的解析过程分析完毕了. 例如有html(template)字符串: <div id="app"> <p>{{ message }}</p> </div> 产出如下: { attrs: [&q

  • vue parseHTML 函数拿到返回值后的处理源码解析

    目录 引言 parseStartTag函数返回值 handleStartTag源码 tagName 及unarySlash 调用parser钩子函数 引言 继上篇文章: parseHTML 函数源码解析 var startTagMatch = parseStartTag(); if (startTagMatch) { handleStartTag(startTagMatch); if (shouldIgnoreFirstNewline(startTagMatch.tagName, html))

  • vue parseHTML函数源码解析 AST预备知识

    目录 正文 createASTElement函数 解析指令所用正则 parse 函数中的变量 正文 接上章节:parseHTML 函数源码解析AST 基本形成 在正式扎进Vue parse源码之前,我们先了解下他周边的工具函数, 这能帮我们快速的去理解阅读. 还记得我们在上章节讲的element元素节点的描述对象吗? var element = { type: 1, tag: tag, parent: null, attrsList: attrs, children: [] } 在源码中定义了一

  • Django contrib auth authenticate函数源码解析

    引言 django提供了一个默认的auth系统用于用户的登录和授权,并提供了一定的扩展性,允许开发者自行定义多个验证后台,每个验证后台必须实现authenticate函数,并返回None或者User对象. 默认的后台是django.contrib.auth.backends.ModelBackend,该后台通过用户名和密码进行用户的验证,以settings.AUTH_USER_MODEL作为模型.但是在实际的开发中,相信大家都不会固定的使用用户名以及同一个model进行验证,比如,不同的角色需要

  • jQuery each函数源码分析

    jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 代码 /*! * jQuery源码分析-each函数 * jQuery版本:1.4.2 * * ---------------------------------------------------------- * 函数介绍 * * each函数通过jQuery.extend函数附加到jQuery对象中: * jQuery.extend({ * each:

  • FilenameUtils.getName 函数源码分析

    目录 一.背景 二.源码分析 2.1 问题1:为什么需要 NonNul 检查 ? 2.1.1 怎么检查的? 2.1.2 为什么要做这个检查呢? 2.2 问题2: 为什么不根据当前系统类型来获取分隔符? 三.Zoom Out 3.1 代码健壮性 3.2 代码严谨性 3.3 如何写注释 四.总结 一.背景 最近用到了 org.apache.commons.io.FilenameUtils#getName 这个方法,该方法可以传入文件路径,获取文件名. 简单看了下源码,虽然并不复杂,但和自己设想略有区

  • Spring源码解析之BeanPostProcessor知识总结

    一.简介 BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口. 实例化Bean做前置处理.后置处理 二.接口定义 @Component public class BeanPost implements BeanPostProcessor { /** * 在每个bean创建之后的初始化方法之前调用 * @param bean 当前实例化的bean * @param beanName bean的名称 * @return 返回实例化的bean或者可以对对象进行再封装返

  • Eureka源码核心类预备知识

    目录 1. 前言 1.1 Eureka的异地多活 1.2 Region和Zone 1.3 Region和AZ需求 2.核心类 2.1 客户端核心类 2.1.1 InstanceInfo-实例信息类 2.1.2 Application 2.1.3 Applications 2.2 服务端 2.2.1 AbstractInstanceRegistry 2.2.2 PeerAwareInstanceRegistryImpl 3. Jersey通信框架 1. 前言 1.1 Eureka的异地多活 异地多

  • Vue中之nextTick函数源码分析详解

    1. 什么是Vue.nextTick()? 官方文档解释如下: 在下次DOM更新循环结束之后执行的延迟回调.在修改数据之后立即使用这个方法,获取更新后的DOM. 2. 为什么要使用nextTick? <!DOCTYPE html> <html> <head> <title>演示Vue</title> <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"&

随机推荐