优秀的编程知识分享平台

网站首页 > 技术文章 正文

Vue源码全面解析三十一 parseHTML函数(解析html(二))

nanyue 2024-08-17 19:12:06 技术文章 20 ℃


我们上一章分析了html解析开始标签的处理,我们本章来看一下结束标签的处理。

以下就是匹配结束标签代码:

 // End tag:
const endTagMatch = html.match(endTag) // 匹配 </ 
if (endTagMatch) {
  // 开始位置
  const curIndex = index
  // 减去对应的长度
  advance(endTagMatch[0].length)
  // 解析结束标签
  parseEndTag(endTagMatch[1], curIndex, index)
  continue
}

我们先简单说一下 parseEndTag 的分析,为了减少篇幅我们就只帖出关键代码了

1、匹配 “stack” 数组里面相同标签名称的对象

 // 转换为小写
lowerCasedTagName = tagName.toLowerCase()
// 匹配相同的tag标签
for (pos = stack.length - 1; pos >= 0; pos--) {
  if (stack[pos].lowerCasedTag === lowerCasedTagName) {
    break
  }
}

2、调用 “end” 函数

 if (options.end) {
   options.end(stack[i].tag, start, end)
 }

那么我们来看一下 “end” 函数的代码:

 end (tag, start, end) {
    // 取出 stack 数组的最后一项
      const element = stack[stack.length - 1]
      // 删除数组的最后一项
      stack.length -= 1
      // 当前标签的附件标签
      currentParent = stack[stack.length - 1]
      if (process.env.NODE_ENV !== 'production' && options.outputSourceRange) {
        // 标签结束位置
        element.end = end
      }
      closeElement(element)
    }

可看到其实主要的工作是在closeElement 函数,我们简单总结一下该函数的功能,先看代码:

function closeElement (element) {
    trimEndingWhitespace(element)
    c
    // tree management
    if (!stack.length && element !== root) {
      // allow root elements with v-if, v-else-if and v-else
      if (root.if && (element.elseif || element.else)) {
        if (process.env.NODE_ENV !== 'production') {
          checkRootConstraints(element)
        }
        addIfCondition(root, {
          exp: element.elseif,
          block: element
        })
      } else if (process.env.NODE_ENV !== 'production') {
        warnOnce(
          `Component template should contain exactly one root element. ` +
          `If you are using v-if on multiple elements, ` +
          `use v-else-if to chain them instead.`,
          { start: element.start }
        )
      }
    }
    if (currentParent && !element.forbidden) {
      if (element.elseif || element.else) {
        processIfConditions(element, currentParent)
      } else {
        if (element.slotScope) {
          // scoped slot
          // keep it in the children list so that v-else(-if) conditions can
          // find it as the prev node.
          const name = element.slotTarget || '"default"'
          ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element
        }
        currentParent.children.push(element)
        element.parent = currentParent
      }
    }

    // final children cleanup
    // filter out scoped slots
    element.children = element.children.filter(c => !(c: any).slotScope)
    // remove trailing whitespace node again
    trimEndingWhitespace(element)

    // check pre state
    if (element.pre) {
      inVPre = false
    }
    if (platformIsPreTag(element.tag)) {
      inPre = false
    }
    // apply post-transforms
    for (let i = 0; i < postTransforms.length; i++) {
      postTransforms[i](element, options)
    }
  }

接下来我们拆分一下该函数。

1、移除子节点是空白节点的标签(node.type === 3 && node.text === '')

代码如下:

  trimEndingWhitespace(element)

2、处理该节点的属性以及指令

代码如下:

 if (!inVPre && !element.processed) {
      element = processElement(element, options)
    }

processElement 函数有如下处理:

1、处理v-bind指令

2、处理 ref 属性

3、处理 slot 插槽一个 slot 标签

4、处理component 组件

5、处理标签属性(attr)

6、是否存在 style和 :style冲突

7、是否存在 class和 :class冲突

class

我们来看看以上代码的作用:

允许根元素具有v-if、v-else-if和v-else。

checkRootConstraints(element)

checkRootConstraints 函数,我们已经看过很多遍了,验证不能是 “slot” 和 “template” 标签,并且不是存在 v-for 指令,这个大家都知道,只能有一个根元素。

 if (element.elseif || element.else) {
   processIfConditions(element, currentParent)
 }

如果 “elseif”指令存在或者“else” 指令存在,就需要 验证是否存在 "v-if" 指令是存在存在,因为他们是对应的。

 element.children = element.children.filter(c => !(c: any).slotScope)

处理子元素的作用域。

 if (platformIsPreTag(element.tag)) {
      inPre = false
    }

是否为平台的 pre 标签。

for (let i = 0; i < postTransforms.length; i++) {
      postTransforms[i](element, options)
    }

最后调用 postTransforms 函数,如果存在的话,

这个我也没搞明白怎么用的,如果有人知道欢迎指点迷津啊,感激不尽。

Tags:

最近发表
标签列表