资讯专栏INFORMATION COLUMN

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

3403771864 / 416人阅读

  承继上篇内容:下面是parseHTML 函数源码解析

  var startTagMatch = parseStartTag();
  if (startTagMatch) {
  handleStartTag(startTagMatch);
  if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) {
  advance(1);
  }
  continue
  }

  在之前这篇文章中写明startTagMatch 就用来获取parseStartTag函数的返回值。并只有在成功匹配到开始标签的情况下parseStartTag 才会返回解析结果(一个对象),否则返回undefined。

  假设有如下html(template)字符串:

  <div id="box" v-if="watings"></div>

  parseStartTag函数返回值

  则parseStartTag函数的返回值如下:

  match = {
  tagName: 'div',
  attrs: [
  [
  'id="box"',
  'id',
  '=',
  'box',
  undefined,
  undefined
  ],
  [
  ' v-if="watings"',
  'v-if',
  '=',
  'watings',
  undefined,
  undefined
  ]
  ],
  start: index,
  unarySlash: undefined,
  end: index
  }

  handleStartTag源码

  如果匹配成功,if语句代码被执行,得出的结果作为参数传递给 handleStartTag 函数,handleStartTag源码如下:

  function handleStartTag(match) {
  var tagName = match.tagName;
  var unarySlash = match.unarySlash;
  if (expectHTML) {
  if (lastTag === 'p' &amp;&amp; isNonPhrasingTag(tagName)) {
  parseEndTag(lastTag);
  }
  if (canBeLeftOpenTag$$1(tagName) &amp;&amp; lastTag === tagName) {
  parseEndTag(tagName);
  }
  }
  var unary = isUnaryTag$$1(tagName) || !!unarySlash;
  var l = match.attrs.length;
  var attrs = new Array(l);
  for (var i = 0; i &lt; l; i++) {
  var args = match.attrs[i];
  var value = args[3] || args[4] || args[5] || '';
  var shouldDecodeNewlines = tagName === 'a' &amp;&amp; args[1] === 'href' ?
  options.shouldDecodeNewlinesForHref :
  options.shouldDecodeNewlines;
  attrs[i] = {
  name: args[1],
  value: decodeAttr(value, shouldDecodeNewlines)
  };
  }
  if (!unary) {
  stack.push({
  tag: tagName,
  lowerCasedTag: tagName.toLowerCase(),
  attrs: attrs
  });
  lastTag = tagName;
  }
  if (options.start) {
  options.start(tagName, attrs, unary, match.start, match.end);
  }
  }

  tagName 及unarySlash

  handleStartTag函数的作用就是处理标签的解析结果,所以它接收parseStartTag函数的返回值作为参数。handleStartTag函数的一开始定义两个常量:tagName 以及 unarySlash:

  var tagName = match.tagName;
  var unarySlash = match.unarySlash;

  通过对于上章节内容解析,tagName 存储解析开始标签的标签名,unarySlash 是判断开始标签是否为一元标签。

  接着是一个if语句块,if语句的判断条件是if (expectHTML),前面说过expectHTML 是parser选项,是一个布尔值,如果为真则该 if 语句块的代码将被执行。但是现在我们暂时不看这段代码,因为这段代码包含 parseEndTag 函数的调用,所以待我们讲解完 parseEndTag 函数之后,再回头来说这段代码。

  在往下定义了三个变量:

  var unary = isUnaryTag$$1(tagName) || !!unarySlash;
  var l = match.attrs.length;
  var attrs = new Array(l);

  变量 unary 是一个布尔值,当它为真时代表着标签是一元标签,否则是二元标签。

  他们通过isUnaryTag来判断,其原理通过传递的标签名判断是否有跟预设标准HTML中规定的那些一元标签一致。

  l 和 attrs ,其中常量 l 的值存储着 match.attrs 数组的长度,而 attrs 常量则是一个与match.attrs数组长度相等的数组。

  这两个常量将被用于接下来的for循环中:

  for (var i = 0; i < l; i++) {
  var args = match.attrs[i];
  var value = args[3] || args[4] || args[5] || '';
  var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ?
  options.shouldDecodeNewlinesForHref :
  options.shouldDecodeNewlines;
  attrs[i] = {
  name: args[1],
  value: decodeAttr(value, shouldDecodeNewlines)
  };
  }

  具体看一下循环体的代码,首先定义 args 常量,它的值就是每个属性的解析结果,即match.attrs 数组中的元素对象。

  变量 value 中就保存着最终的属性值,如果第4、5、6 项都没有获取到属性值,那么属性值将被设置为一个空字符串:''。

  属性值获取到了之后,就可以拼装最终的 attrs 数组。

  attrs 数组的每个元素对象只包含两个元素,即属性名 name 和属性值 value ,对于属性名直接从 args[1] 中即可获取,但我们发现属性值却没有直接使用前面获取到的 value ,而是将传value 递给了decodeAttr 函数,并使用该函数的返回值作为最终的属性值。

  decodeAttr 函数的作用是对属性值中所包含的 html 实体进行解码,将其转换为实体对应的字符。关于 shouldDecodeNewlinesForHref 与 shouldDecodeNewlines 可回顾章节

  接下来是:

  if (!unary) {
  stack.push({
  tag: tagName,
  lowerCasedTag: tagName.toLowerCase(),
  attrs: attrs
  });
  lastTag = tagName;
  }

  这个if条件是当开始标签是非一元标签时才会执行,其目的是: 如果开始标签是非一元标签,则将该开始标签的信息入栈,即push到stack数组中,并将lastTag的值设置为该标签名。

  在讲解 parseHTML 函数开头定义的变量和常量的过程中,我们讲解过 stack 常量以及lastTage 变量,其目的是将来判断是否缺少闭合标签,并且现在大家应该知道为什么 lastTag 所存储的标签名字始终保存着 stack 栈顶的元素了。

  调用parser钩子函数

  最后一段代码调用parser钩子函数的:

  if (options.start) {
  options.start(tagName, attrs, unary, match.start, match.end);
  }

  当 parser 选项中包含 options.start 函数,表示调用,同时将开始标签的名字命名为tagName ,当格式化后的属性数组为 attrs。那是不是一元标签 unary ,且开始标签的开始和技术位置是在原 html 中match.start 和 match.end 作为参数传递。


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/127766.html

相关文章

  • 【Vue原理】Filters - 源码

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版嗨,又到周末啦,又可以睡 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    oujie 评论0 收藏0
  • 【Vue原理】Slot - 白话版

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理白话版插槽作为组件一个重要的部 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    chanthuang 评论0 收藏0
  • 【Filecoin源码仓库全解析】第三章(上):存储提供方(矿工)的配置操作

    摘要:我们会在后面的源码仓库全解析第三章下存储提供方矿工的配置操作章节重点介绍这个过程。参考文献本章赞助品牌深圳牛链科技有限公司,是一家专注存储类矿机研发生产销售托管为一体的高科技企业。感谢深圳牛链科技有限公司对嘉乐的原创内容提供支持。 欢迎大家来到第三章,经过 前章《【Filecoin源码仓库全解析】第二章:如何创建账户钱包并获取FIL Mock代币的内容阅读后,我们应该能顺利在Filec...

    rose 评论0 收藏0
  • 深入理解react

    摘要:最近在看源码,发觉以前对的理解实在浮浅,这里记录了一些以前疏忽的点。和在里面,经过的解析后,会变成执行后的结果。原来对的理解就是类似这种写法,现在看了实现之后才理解。 最近在看react源码,发觉以前对react的理解实在浮浅,这里记录了一些以前疏忽的点。 createElement和component 在react里面,经过babel的解析后,jsx会变成createElement执...

    CoderStudy 评论0 收藏0
  • 一个有味道的函数

    摘要:所以我们分析这个新需求的效果我们在函数执行到一半时,执行了,的返回值为后续函数的执行返回值。也就是说,我们在中处理,直接调用队列中的下一个函数即可然后监听和回调,即可在当前函数中获取到返回值拿到返回值后就可以执行我们后续的代码。 最近想到了一个自认为很有意思的面试题如何实现一个compose函数。函数接收数个参数,参数均为Function类型,右侧函数的执行结果将作为左侧函数执行的参数...

    megatron 评论0 收藏0

发表评论

0条评论

3403771864

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<