我們先來看看代碼 “src/platforms/web/compiler/directives”目錄下面包含html.js
和text.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)
}
}
可以看到上面就是定義了兩個函數(shù)心包,分別傳入了3各參數(shù):
1身辨、 el
類型是ASTElement
2、_s
函數(shù)还惠,就是一個將值轉(zhuǎn)換為string
類型的方法饲握,
3、dir
類型是ASTDirective
可以看到上面的函數(shù)都調(diào)用了一個addProp
方法蚕键,addProp
函數(shù)的作用就是向el.props
推入(push)dir
對象救欧。
模板編譯的時候,就是我們之前的vue源碼分析(十六)核心函數(shù)之Compiler這一步的時候會把props
添加到domProps
對象上面锣光。
v-html 和 v-text 的更新是通過
updateDOMProps
函數(shù)來進行更新的笆怠,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是被觀察的一個對象蹬刷,就進行一個拷貝
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é)點具有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é)省篇幅诈火,下面我們就挑一些重點的。
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的值用戶是不能改變的,那就沒有必調(diào)用shouldUpdateValue
來更新蜡娶。
elm[key] = cur
最后給elm
真實的DOM節(jié)點設(shè)置混卵,textContent
或者innerHTML
屬性的值。