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

我们先来看看代码 “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 = `${cur}`
      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  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))