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)
  }
}

可以看到上面就是定義了兩個(gè)函數(shù),分別傳入了3各參數(shù):
1、 el 類型是ASTElement
2、_s函數(shù),就是一個(gè)將值轉(zhuǎn)換為string類型的方法,
3、dir類型是ASTDirective

可以看到上面的函數(shù)都調(diào)用了一個(gè)addProp方法,addProp函數(shù)的作用就是向el.props推入(push)dir對象。
模板編譯的時(shí)候,就是我們之前的vue源碼分析(十六)核心函數(shù)之Compiler這一步的時(shí)候會把props添加到domProps對象上面。

v-html 和 v-text 的更新是通過updateDOMProps函數(shù)來進(jìn)行更新的,updateDOMProps又是通過render來觸發(fā)的。

下面是 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是被觀察的一個(gè)對象,就進(jìn)行一個(gè)拷貝
  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]
    //如果節(jié)點(diǎn)具有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) {}
    }
  }
}

一般的代碼分析,我就直接在代碼里面的注釋寫了,為了節(jié)省篇幅,下面我們就挑一些重點(diǎn)的。

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、清空里面的真實(shí)子級

 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的情況,一般是表單類的標(biāo)簽,但是PROGRESS進(jìn)度條標(biāo)簽頁存在value屬性,所有需要過濾,因?yàn)镻ROGRESS的值用戶是不能改變的,那就沒有必調(diào)用shouldUpdateValue來更新。

elm[key] = cur

最后給elm真實(shí)的DOM節(jié)點(diǎn)設(shè)置,textContent或者innerHTML屬性的值。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容