vue.js 3设计与实现 -- 挂载与更新(一)

vue.js 3设计与实现 – 渲染器的设计这章中,我们主要介绍了渲染器的基本概念和整体架构。本章,我们将讲解渲染器的核心功能:挂载与更新。

一、挂载子节点和元素的属性

vue.js 3设计与实现 – 渲染器的设计这章提到,当 vnode.children 的值是字符串类型时,会把它设置为元素的文本内容。一个元素除了具有文本子节点外,还可以包含其他元素子节点,并且子节点可以是很多个。为了描述元素的子节点,我们需要将 vnode.children 定义为数组:

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

​ 上面这段代码描述的是“一个 div 标签具有一个子节点,且子节点是 p 标签”。可以看到, 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) 
}

​ 在上面这段代码中,我们增加了新的判断分支。使用 Array.isArray 函数判断 vnode.children 是否是数组,如果是数组,则循环遍历它,并调 patch 函数挂载数组中的虚拟节点。在挂载子节点时,需要注意以下两点。

  • 传递给 patch 函数的第一个参数是 null。因为是挂载阶段,没有旧 vnode,所以只需要传递 null 即可。这样,当 patch 函数执行时,就会递归地调用 mountElement 函数完成挂载。

  • 传递给 patch 函数的第三个参数是挂载点。由于我们正在挂载的子元素是 div 标签的子节点,所以需要把刚刚创建的 div 元素作为挂载点,这样才能保证这些子节点挂载到正确位置。

​ 完成了子节点的挂载后,我们再来看看如何用 vnode 描述一个标签的属性,以及如何渲染这些属性。我们知道, HTML 标签有很多属性,其中有些属性是通用的,例如 id、class 等,而有些属性是特定元素才有的,例如 form 元素的 action 属性。实际上,渲染一个元素的属性比想象中要复杂,不过我们仍然秉承一切从简的原则,先来看看最基本的属性处理。
​ 为了描述元素的属性,我们需要为虚拟 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) 
} 

​ 在这段代码中,我们首先检查了 vnode.props 字段是否存在,如果存在则遍历它,并调用 setAttribute 函数将属性设置到元素上。实际上,除了使用 setAttribute 函数为元素

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值