【vue设计与实现】挂载和更新 1-挂载子节点和元素的属性&&HTML Attributes与DOM Properties

前面提到,当vnode.children的值是字符串类型时,会把它设置为元素的文本内容。但是一个元素还可以包含其他元素子节点,并且子节点可以是很多个。为了描述元素的子节点,我们需要将vnode.children定义为数组:

const vnode = {
	type: 'div',
	children: [
		{
			type: 'p',
			children: 'hello'
		}
	]
}

可以看到vnode.children是一个数组,它的每一个元素都是一个独立的虚拟节点对象。这样就形成了树型结构,即虚拟DOM树。
为了完成子节点的渲染,需要修改mountElement函数,如下面代码所示:

function mountElement(vnode, container){
	const el = createElement(vnode,type)
	if(typeof vnode.children === 'string'){
		setElementText(el, vnode, children)
	}else if(Array.isArray(vnode.children)){
		// 如果children是数组,就进行遍历,并调用patch函数来挂载它们
		vnode.children.forEach((child)=>{
			patch(null,child,el)
		})
	}
	insert(el,container)
}

如果是数组,则循环遍历它,并调patch函数挂载数组中的虚拟节点,在挂载子节点时,需要注意以下两点:

  1. 传递给patch函数的第一个参数是null。这时patch函数执行时,就会递归地调用mountElement函数完成挂载
  2. 传递给patch函数的第三个参数是挂载点。由于正在挂载的子元素是div标签的子节点,所以要把刚创建的div元素作为挂载点。

再来看vnode描述一个标签的属性,以及如何渲染这些属性。HTML标签有很多属性,有些属性是特定元素才有的。实际上,渲染一个元素的属性比想象中要复杂,不过我们先来看看最基本的属性处理。
为了描述元素的属性,为虚拟DOM定义新的vnode.props字段,如下面代码所示:

const vnode = {
	type: 'div',
	// 使用props描述一个元素的属性
	props:{
		id: 'foo'
	},
	children: {
		{
			type: 'p',
			children: 'hello'
		}
	}
}

vnode.props是一个对象,它的键代表元素的属性名称,值代表对应属性的值。这样,就可以通过遍历props对象的方式,把这些属性渲染到对应的元素上,如下面代码所示:

function mountElement(vnode, container){
	const el = createElement(vnode,type)
	// 省略children的处理
	
	// 如果 vnode.props存在才处理它
	if (vnode.props){
		// 遍历 vnode.props
		for(const key in vnode.props){
			// 调用 setAttribute 将属性设置到元素上
			el.setAttribute(key, vnode.props[key])
		}
	}
	insert(el,container)
}

知识扩展
setAttribute() 方法创建或改变某个新属性。
element.setAttribute(attributename,attributevalue)

当然也可以通过DOM对象直接设置,如下:

el[key] = vnode.props[key]

其实无论是使用setAttribute函数,还是直接操作DOM对象,都存在缺陷。不过在讨论具体有哪些缺陷前,先要搞清楚HTML Attributes 和 DOM Properties

HTML Attributes 和 DOM Properties

HTML Attributes值的是定义在HTML标签上的属性,例如

<input id="my-input" type="text" value="foo" />

HTML Attribute值的是 id=“my-input” ,type="text"和value=“foo”
当浏览器解析这段HTML代码后,会创建一个与之相符的DOM元素对象,所以可以通过JavaScript代码来读取改DOM对象

const el = document.querySelector('#my-input')

这个DOM包含很多属性,这些属性就是DOM Properties
很多HTML Attributes在DOM对象上有与之同名的DOM Properties,例如id="my-input"对应el.id,type="text"对应el.type,value="foo"对应el.value等,但也不是总是一模一样的,例如

<div class="foo"></div>

class="foo"对应的DOM Properties则是el.className。

此外也不是所有HTML Attributes都有对应的DOM Properties,例如:

<div aria-valuenow="75"></div>

aria.* 类的HTML Attributes就没有与之对应的DOM Properties,反之亦然

同时把这种HTML Attributres和DOM Properties具有相同名称的属性看作是直接映射,但并不是所有HTML Attributes与DOM Propeties之间都是直接映射的关系,例如:

<input value="foo" />

这里如果用户没有修改文本框的内容,那么通过el.value读取对应的DOM Properties的值是‘foo’,如果用户修改了文本框的值,那么el.value的值就是当前文本框的值,例如将文本框的内容修改为’bar’:

console.log(el.value) // bar

但是看下面的代码

console.log(el.getAttribute('value')) // 仍然是foo

可以发现,用户对文本框内容的修改不会影响el.getAttribute(‘value’)的返回值,实际上HTML Attributes的作用是设置与之对应的DOM Properties初始值,一旦改变,那么DOM Properties始终存储的是当前值,而通过getAttribute函数得到的仍然是初始值。
但仍可以通过el.defaultValue来访问初始值
这说明HTML Attributes可能关联多个DOM Properties。

总而言之,只要记住HTML Attributes的作用是设置与之对应的DOM Properties初始值

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值