我们先来看看代码 “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)
}
}
可以看到上面就是定义了两个函数,分别传入了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
属性的值。
网友评论