[前端] vueparseHTML函数拿到返回值后的处理源码解析

1964 0
黑夜隐士 2022-10-21 15:42:55 | 显示全部楼层 |阅读模式
目录

    引言
      parseStartTag函数返回值handleStartTag源码tagName 及unarySlash调用parser钩子函数



引言

继上篇文章:
parseHTML 函数源码解析
  1. var startTagMatch = parseStartTag();
  2. if (startTagMatch) {
  3.         handleStartTag(startTagMatch);
  4.         if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) {
  5.                 advance(1);
  6.         }
  7.         continue
  8. }
复制代码
在上个章节中知道startTagMatch 就是获取parseStartTag函数的返回值。并只有在成功匹配到开始标签的情况下parseStartTag 才会返回解析结果(一个对象),否则返回undefined。
假设有如下html(template)字符串:
  1. <div id="box" v-if="watings"></div>
复制代码
parseStartTag函数返回值

则parsStartTag函数的返回值如下:
  1. match = {
  2.   tagName: 'div',
  3.   attrs: [
  4.     [
  5.       'id="box"',
  6.       'id',
  7.       '=',
  8.       'box',
  9.       undefined,
  10.       undefined
  11.     ],
  12.     [
  13.       ' v-if="watings"',
  14.       'v-if',
  15.       '=',
  16.       'watings',
  17.       undefined,
  18.       undefined
  19.     ]
  20.   ],
  21.   start: index,
  22.   unarySlash: undefined,
  23.   end: index
  24. }
复制代码
handleStartTag源码

现在我们假设匹配成功,那么if语句块中的代码将会被执行,此时会将解析结果作为参数传递给 handleStartTag 函数,handleStartTag源码如下:
  1. function handleStartTag(match) {
  2.         var tagName = match.tagName;
  3.         var unarySlash = match.unarySlash;
  4.         if (expectHTML) {
  5.                 if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
  6.                         parseEndTag(lastTag);
  7.                 }
  8.                 if (canBeLeftOpenTag$$1(tagName) && lastTag === tagName) {
  9.                         parseEndTag(tagName);
  10.                 }
  11.         }
  12.         var unary = isUnaryTag$$1(tagName) || !!unarySlash;
  13.         var l = match.attrs.length;
  14.         var attrs = new Array(l);
  15.         for (var i = 0; i < l; i++) {
  16.                 var args = match.attrs[i];
  17.                 var value = args[3] || args[4] || args[5] || '';
  18.                 var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ?
  19.                         options.shouldDecodeNewlinesForHref :
  20.                         options.shouldDecodeNewlines;
  21.                 attrs[i] = {
  22.                         name: args[1],
  23.                         value: decodeAttr(value, shouldDecodeNewlines)
  24.                 };
  25.         }
  26.         if (!unary) {
  27.                 stack.push({
  28.                         tag: tagName,
  29.                         lowerCasedTag: tagName.toLowerCase(),
  30.                         attrs: attrs
  31.                 });
  32.                 lastTag = tagName;
  33.         }
  34.         if (options.start) {
  35.                 options.start(tagName, attrs, unary, match.start, match.end);
  36.         }
  37. }
复制代码
tagName 及unarySlash

handleStartTag函数用来处理开始标签的解析结果,所以它接收parseStartTag函数的返回值作为参数。handleStartTag函数的一开始定义两个常量:tagName 以及 unarySlash:
  1. var tagName = match.tagName;
  2. var unarySlash = match.unarySlash;
复制代码
根据上章节的内容就能理解,tagName 存储解析开始标签的标签名,unarySlash 可以根据他的值判断是解析的开始标签是否为一元标签。
接着是一个if语句块,if语句的判断条件是if (expectHTML),前面说过expectHTML 是parser选项,是一个布尔值,如果为真则该 if 语句块的代码将被执行。但是现在我们暂时不看这段代码,因为这段代码包含 parseEndTag 函数的调用,所以待我们讲解完 parseEndTag 函数之后,再回头来说这段代码。
在往下定义了三个变量:
  1. var unary = isUnaryTag$$1(tagName) || !!unarySlash;
  2. var l = match.attrs.length;
  3. var attrs = new Array(l);
复制代码
变量 unary 是一个布尔值,当它为真时代表着标签是一元标签,否则是二元标签。
他们通过isUnaryTag来判断,其原理通过传递的标签名判断是否有跟预设标准HTML中规定的那些一元标签一致。
l 和 attrs ,其中常量 l 的值存储着 match.attrs 数组的长度,而 attrs 常量则是一个与match.attrs数组长度相等的数组。
这两个常量将被用于接下来的for循环中:
  1. for (var i = 0; i < l; i++) {
  2.         var args = match.attrs[i];
  3.         var value = args[3] || args[4] || args[5] || '';
  4.         var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ?
  5.                 options.shouldDecodeNewlinesForHref :
  6.                 options.shouldDecodeNewlines;
  7.         attrs[i] = {
  8.                 name: args[1],
  9.                 value: decodeAttr(value, shouldDecodeNewlines)
  10.         };
  11. }
复制代码
具体看一下循环体的代码,首先定义 args 常量,它的值就是每个属性的解析结果,即match.attrs 数组中的元素对象。
变量 value 中就保存着最终的属性值,如果第4、5、6 项都没有获取到属性值,那么属性值将被设置为一个空字符串:''。
属性值获取到了之后,就可以拼装最终的 attrs 数组。
attrs 数组的每个元素对象只包含两个元素,即属性名 name 和属性值 value ,对于属性名直接从 args[1] 中即可获取,但我们发现属性值却没有直接使用前面获取到的 value ,而是将传value 递给了decodeAttr 函数,并使用该函数的返回值作为最终的属性值。
decodeAttr 函数的作用是对属性值中所包含的 html 实体进行解码,将其转换为实体对应的字符。关于 shouldDecodeNewlinesForHref 与 shouldDecodeNewlines 可回顾章节
Vue编译器源码分析compileToFunctions作用
接下来是:
  1. if (!unary) {
  2.         stack.push({
  3.                 tag: tagName,
  4.                 lowerCasedTag: tagName.toLowerCase(),
  5.                 attrs: attrs
  6.         });
  7.         lastTag = tagName;
  8. }
复制代码
这个if条件是当开始标签是非一元标签时才会执行,其目的是: 如果开始标签是非一元标签,则将该开始标签的信息入栈,即push到stack数组中,并将lastTag的值设置为该标签名。
在讲解 parseHTML 函数开头定义的变量和常量的过程中,我们讲解过 stack 常量以及lastTage 变量,其目的是将来判断是否缺少闭合标签,并且现在大家应该知道为什么 lastTag 所存储的标签名字始终保存着 stack 栈顶的元素了。

调用parser钩子函数

最后一段代码调用parser钩子函数的:
  1. if (options.start) {
  2.         options.start(tagName, attrs, unary, match.start, match.end);
  3. }
复制代码
如果 parser 选项中包含 options.start 函数,则调用之,并将开始标签的名字 tagName ,格式化后的属性数组 attrs ,是否为一元标签 unary ,以及开始标签在原 html 中的开始和结束位置match.start 和 match.end 作为参数传递。
接下来我们分析 parse 到结束标签之后会怎么做。
parseHTML 函数源码解析之解析器遇到结束标签
以上就是vue parseHTML 函数源码解析的详细内容,更多关于vue parseHTML 函数的资料请关注中国红客联盟其它相关文章!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行