0%

Vue挂载子节点和元素属性

渲染器的核心功能就是挂载与更新

首先,有一个虚拟dom的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
const vnode = {
type:'div',
//使用props描述一个元素得特性
props:{
id:'foo'
},
children:[
{
type:'p',
children:'hello'
}
]
}

检查vnode.props字段可以使用el[key]=vnode.props[key]或者el.setAttribute(key,vnode.props[key]),先来了解下HTML Attributes和DOM Properties的不同

HTML Attributes和DOM Properties

1
<div id="foo"></div>

这个DOM对象有很多属性,HTML Attributes在DOM对象上有与之同名的DOM Properties,例如id=”my-input”对应el.id,但DOM Properties并不与HTML Attributes的名字总是一样,例如

1
2
3
<div class="foo">

</div>

class=’foo’对应的DOM Properties是el.className,不是所有的HTML Adttributes都有和它对应的DOM Properties,例如aria-*类的HTML Attributes就没有和它对应的DOM Properties

1
<input value='foo'/>

当用户修改了文本框的值,那么el.value的值时当前文本的值,而el.getAttribute(‘value’)仍然是之前的值

总之:HTML Attributes的作用是设置与之对应的DOM Properties的初始值

正确设置元素的属性

例子:

1
2
3
<button :disabled='false'>
Button
</button>

这个HTML模板会被编译成vnode:

1
2
3
4
5
6
const button = {
type: 'button',
props: {
disabled:false
}
}

这里的props.disabled的值时空字符串,如果在渲染器中调用setAttribute函数设置属性,相当于:

1
el.setAttribute('disabled',false)

用户本意是不禁用,但是用setAttribute按钮仍然被禁用了,这是因为使用setAttribute函数设置的值总是会被字符串化,等价于

1
el.setAttribute('disabled','false')

el.disabled的值时布尔值,我们不关心值是什么,只要disabled属性存在,按钮就被禁用,不使用setAttribute,用el.disabled=false

但是如果是下面的模板:

1
2
3
<button disabled>
Button
</button>

对应的vnode:

1
2
3
4
5
6
const button = {
type:'button',
props: {
disabled: ''
}
}

用DOM Properties设置元素属性时,el.disabled=’’,类型转换会设置为el.disabled=false,用户本意是禁用按钮,则只能优先设置setAttribute,如果是空字符串则手动矫正

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function mountElement(vnode,container) {
const el = createElement(vnode.type)
//省略children处理
if(vnode.props){
for(const key in vnode.props){
if(key in vnode.props){
//用in操作判断key是否存在对应的DOM Properties
if(key in el){
//获取该DOM Properties的类型
const type = el[key]
const value = vnode.props[key]
if(type === 'boolean' && value ===''){
e[key]=true
}else{
e[key]=value
}
}else{
el.setAttribute(key,vnode.props[key])
}

}
}
}
insert(el,container)
}