在说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 parseHTML函数源码解析AST更多内容。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/127762.html
写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Compile - 源码版 之 Parse 主要流程 本文难度较繁琐,需要耐心观看,如果你对 compile 源码暂时...
摘要:下面用具体代码进行分析。匹配不到那么就是开始标签,调用函数解析。如这里的转化为加上是为了的下一步转为函数,本文中暂时不会用到。再把转化后的内容进。 什么是AST 在Vue的mount过程中,template会被编译成AST语法树,AST是指抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式。...
vue parseHTML函数解析器遇到结束标签,在之前文章中已讲述完毕。 例如有html(template)字符串: <divid="app"> <p>{{message}}</p> </div> 产出如下: { attrs:["id="app"","id...
摘要:模板解析器原理本文来自深入浅出模板编译原理篇的第九章,主要讲述了如何将模板解析成,这一章的内容是全书最复杂且烧脑的章节。循环模板的伪代码如下截取模板字符串并触发钩子函数为了方便理解,我们手动模拟解析器的解析过程。 Vue.js 模板解析器原理 本文来自《深入浅出Vue.js》模板编译原理篇的第九章,主要讲述了如何将模板解析成AST,这一章的内容是全书最复杂且烧脑的章节。本文未经排版,真...
直接进入核心现在说说baseCompile核心代码: //`createCompilerCreator`allowscreatingcompilersthatusealternative //parser/optimizer/codegen,e.gtheSSRoptimizingcompiler. //Herewejustexportadefaultcompilerusingthede...
阅读 543·2023-03-27 18:33
阅读 729·2023-03-26 17:27
阅读 627·2023-03-26 17:14
阅读 589·2023-03-17 21:13
阅读 518·2023-03-17 08:28
阅读 1793·2023-02-27 22:32
阅读 1285·2023-02-27 22:27
阅读 2171·2023-01-20 08:28