zoukankan      html  css  js  c++  java
  • v-text、v-html、v-cloak、v-pre.md

    本篇文章,我们简单的介绍几个Vue内置指令的实现。

    v-text

    v-text的用法很简单,以下两个表达式的作用相同。

    <span v-text="msg"></span>
    <span>{{msg}}</span>

    和所有普通指令一样,在生成ast时,v-text会被解析到el.directives中。

    但在生成render函数的过程中,在解析属性时,

    我们会首先解析指令。genDirectives方法中有如下一段代码:

    const gen: DirectiveFunction = platformDirectives[dir.name] || baseDirectives[dir.name]
    if (gen) {
      // compile-time directive that manipulates AST.
      // returns true if it also needs a runtime counterpart.
      needRuntime = !!gen(el, dir, warn)
    }
    if (needRuntime) {
      hasRuntime = true
      res += `...`
    }

    directives概述中我们也提到过,platformDirectivesbaseDirectives会对部分内置指令进行处理。v-text就是其中之一。

    最终的gen函数如下所示:

    export default function text (el: ASTElement, dir: ASTDirective) {
      if (dir.value) {
        addProp(el, 'textContent', `_s(${dir.value})`)
      }
    }

    该函数返回的是undefined,所以needRuntime最终是false,所以该结果不会添加到res上。

    addProp的定义如下:

    export function addProp (el: ASTElement, name: string, value: string) {
      (el.props || (el.props = [])).push({ name, value })
    }

    它会给el.props数组中添加一个对象,对象里保存的namevalue

    // DOM props
    if (el.props) {
      data += `domProps:{${genProps(el.props)}},`
    }

    最终,会添加到domProps对应的数组中。上面例子中的span,最终生成的render函数如下:

    _c('span',{domProps:{"textContent":_s(msg)}})

    patch过程中的处理,和其他data中的数据一样,是通过钩子函数处理的。

    function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
      if (!oldVnode.data.domProps && !vnode.data.domProps) {
        return
      }
      let key, cur
      const elm: any = vnode.elm
      const oldProps = oldVnode.data.domProps || {}
      let props = vnode.data.domProps || {}
      // clone observed objects, as the user probably wants to mutate it
      if (props.__ob__) {
        props = vnode.data.domProps = extend({}, props)
      }
    
      for (key in oldProps) {
        if (props[key] == null) {
          elm[key] = ''
        }
      }
      for (key in props) {
        cur = props[key]
        if (key === 'textContent' || key === 'innerHTML') {
          if (vnode.children) vnode.children.length = 0
          if (cur === oldProps[key]) continue
        }
    
        if (key === 'value') {
          // store value as _value as well since
          // non-string values will be stringified
          elm._value = cur
          // avoid resetting cursor position when value is the same
          const strCur = cur == null ? '' : String(cur)
          if (shouldUpdateValue(elm, vnode, strCur)) {
            elm.value = strCur
          }
        } else {
          elm[key] = cur
        }
      }
    }

    首先会重置oldPropsprops上不存在的属性。然后遍历props中的属性,如果keytextContentinnerHTML,则清除children的内容。

    如果key === 'value'这里应该对inputselect等标签的特殊处理。否则,直接设置elm.textContent = cur,以此来改变文本内容。

    v-html

    v-htmlv-text的用法和处理流程基本完全一样,唯一的区别就是最终v-html设置的elm.innerHTML = cur

    用法示例如下:

    <span v-html="msg"></span>

    v-cloak

    这个指令用的比较少,不懂的人看完官方文档的说明可能还是稀里糊涂的。它的ast生成和上面讲的普通指令一样,在genDirectives时,baseDirectives中包含了cloak,但最终返回的gen是一个空函数。最终它也不会添加到directives数组中,之后也就没有了对它的处理。

    因为我们的模板再编译的过程中,页面中是会显示Mustache 标签的。该指令就是在模板编译之后,被删除。我们可以添加[v-cloak] { display: none },来防止用户感知到Mustache 标签 出现。

    v-pre

    v-pre表示该会跳过该标签及其子元素的编译。

    在编译模板时的start回调函数中,有如下片段:

    if (!inVPre) {
      processPre(element)
      if (element.pre) {
        inVPre = true
      }
    }
     if (inVPre) {
       processRawAttrs(element)
     } else {
       ...
     }

    processPre函数会获取element上的v-pre属性,如果有则设置element.pre = true,同时设置inVPre = true

    接下来的处理,会走进processRawAttrs函数。else块内对各种指令、属性等的处理,都不会执行。

    function processRawAttrs (el) {
      const l = el.attrsList.length
      if (l) {
        const attrs = el.attrs = new Array(l)
        for (let i = 0; i < l; i++) {
          attrs[i] = {
            name: el.attrsList[i].name,
            value: JSON.stringify(el.attrsList[i].value)
          }
        }
      } else if (!el.pre) {
        // non root node in pre blocks with no attributes
        el.plain = true
      }
    }

    这里是对属性的处理,如果el.attrsList不为空数组,则直接循环el.attrsList上的属性添加到el.attrs上。否则,如果当前元素没有设置v-pre指令(是设置v-pre元素的子元素),则设置el.plain = true

    因为我们不编译的是整个子树,而不是单个元素。Vue中就是通过inVPre来标示的,我们parse的整个过程就是入栈出栈,当子元素都编译完,会走到当前元素的end处理,此时再设置inVPre = false,来结束不编译的内容。

  • 相关阅读:
    Web API框架学习——消息管道(二)
    Web API框架学习——路由(一)
    【转】Lucene.NET详细使用与优化详解
    ASP.NET MVC 创建控制器类过程
    ASP.NET MVC创建视图过程
    ORM映射设计思想
    UWP--集合绑定数据
    UWP--MVVM简单计算器
    UWP--数据绑定的几种方式
    一个自动管理学生信息的控制台应用程序(C语言)Label:Water
  • 原文地址:https://www.cnblogs.com/dhsz/p/7697741.html
Copyright © 2011-2022 走看看