美文网首页
vue源码分析(二十二)Vue之指令(v-text、v-html

vue源码分析(二十二)Vue之指令(v-text、v-html

作者: vue爱好者 | 来源:发表于2020-04-22 08:25 被阅读0次

    我们先来看看代码 “src/platforms/web/compiler/directives”目录下面包含html.jstext.js,代码分别如下:

    html.js

    /* @flow */
    
    import { addProp } from 'compiler/helpers'
    
    export default function html (el: ASTElement, dir: ASTDirective) {
      if (dir.value) {
        addProp(el, 'innerHTML', `_s(${dir.value})`, dir)
      }
    }
    

    text.js

    /* @flow */
    
    import { addProp } from 'compiler/helpers'
    
    export default function text (el: ASTElement, dir: ASTDirective) {
      if (dir.value) {
        addProp(el, 'textContent', `_s(${dir.value})`, dir)
      }
    }
    

    可以看到上面就是定义了两个函数,分别传入了3各参数:
    1、 el 类型是ASTElement
    2、_s函数,就是一个将值转换为string类型的方法,
    3、dir类型是ASTDirective

    可以看到上面的函数都调用了一个addProp方法,addProp函数的作用就是向el.props推入(push)dir对象。
    模板编译的时候,就是我们之前的vue源码分析(十六)核心函数之Compiler这一步的时候会把props添加到domProps对象上面。

    v-html 和 v-text 的更新是通过updateDOMProps函数来进行更新的,updateDOMProps又是通过render来触发的。

    下面是 updateDOMProps的代码:

    function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
     // 如果都不存在domProps对象的话,就不往下走了
      if (isUndef(oldVnode.data.domProps) && isUndef(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
      // 如果是props是被观察的一个对象,就进行一个拷贝
      if (isDef(props.__ob__)) {
        props = vnode.data.domProps = extend({}, props)
      }
     // 如果新对象props上面不存在,那就置为空
      for (key in oldProps) {
        if (!(key in props)) {
          elm[key] = ''
        }
      }
    
      for (key in props) {
        cur = props[key]
        //如果节点具有textContent或innerHTML,则忽略子级,这就是
        if (key === 'textContent' || key === 'innerHTML') {
          if (vnode.children) vnode.children.length = 0
          if (cur === oldProps[key]) continue
          if (elm.childNodes.length === 1) {
            elm.removeChild(elm.childNodes[0])
          }
        }
    
        if (key === 'value' && elm.tagName !== 'PROGRESS') {
          // 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 = isUndef(cur) ? '' : String(cur)
          if (shouldUpdateValue(elm, strCur)) {
            elm.value = strCur
          }
        } else if (key === 'innerHTML' && isSVG(elm.tagName) && isUndef(elm.innerHTML)) {
          // IE doesn't support innerHTML for SVG elements
          svgContainer = svgContainer || document.createElement('div')
          svgContainer.innerHTML = `<svg>${cur}</svg>`
          const svg = svgContainer.firstChild
          while (elm.firstChild) {
            elm.removeChild(elm.firstChild)
          }
          while (svg.firstChild) {
            elm.appendChild(svg.firstChild)
          }
        } else if (
          // skip the update if old and new VDOM state is the same.
          // `value` is handled separately because the DOM value may be temporarily
          // out of sync with VDOM state due to focus, composition and modifiers.
          // This  #4521 by skipping the unnecesarry `checked` update.
          cur !== oldProps[key]
        ) {
          // some property updates can throw
          // e.g. `value` on <progress> w/ non-finite value
          try {
            elm[key] = cur
          } catch (e) {}
        }
      }
    }
    

    一般的代码分析,我就直接在代码里面的注释写了,为了节省篇幅,下面我们就挑一些重点的。

    if (key === 'textContent' || key === 'innerHTML') {
          if (vnode.children) vnode.children.length = 0
          if (cur === oldProps[key]) continue
          if (elm.childNodes.length === 1) {
            elm.removeChild(elm.childNodes[0])
          }
        }
    

    从上面的代码可以看到如果是textContent(v-text)或者innerHTML(v-html)
    1、清空里面的虚拟子级
    2、如果值没有改变,就跳过
    3、清空里面的真实子级

     if (key === 'value' && elm.tagName !== 'PROGRESS') {
          // 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 = isUndef(cur) ? '' : String(cur)
          if (shouldUpdateValue(elm, strCur)) {
            elm.value = strCur
          }
        }
    

    key等于value的情况,一般是表单类的标签,但是PROGRESS进度条标签页存在value属性,所有需要过滤,因为PROGRESS的值用户是不能改变的,那就没有必调用shouldUpdateValue来更新。

    elm[key] = cur
    

    最后给elm真实的DOM节点设置,textContent或者innerHTML属性的值。

    相关文章

      网友评论

          本文标题:vue源码分析(二十二)Vue之指令(v-text、v-html

          本文链接:https://www.haomeiwen.com/subject/gmqjuhtx.html