基于snabbdom的diff算法的学习笔记-01h函数和虚拟节点

h函数、vnode节点、createElement

一、vnode节点

vnode是js对象中的一个普通对象,这个对象描述了网页中的真实DOM。本次笔记只涵盖最基本的vnode对象,对象包含sel(DOM标签)

,data(DOM的某些属性,如key,href等),text(DOM的内部文本), children(?Array)

,elm(vnode指向的真实节点)。基于此,可以得到基本的vnode函数:

// vnode.js
export default function vnode(sel, data, children, text, elm) {
    // 将key取出,方便后续使用
    const key = data.key
    return {
        sel,
        data,
        children,
        text,
        elm,
        key
    }
}

二、h函数

h函数是一个函数,通过调用函数的方式生成vnode树。

常见的vnode调用:

h('h1', {}, '我是一个标题')
h('ul', {}, [
   h('li', { key: 'A'}, '我是A'),
   h('li', { key: 'B'}, '我是B'),
   h('li', { key: 'C'}, '我是C'),
])
h('p', {}, h('span', {}, '我是文本'))

本次笔记只适用于以上三种h函数的调用,基于此得到基本的h函数

// h.js 每个h函数只需要考虑单层元素能否生成正确的vnode节点,子元素在调用时自己会重新调用h函数,如例子所示: h({ li, { key: 'A'}, '我是B'})
import vnode from "./vnode";
/**
 * 
 * @param {*} sel 
 * @param {*} data 
 * @param {*} c 
 * h(sel, {}, text | Array | h())
 */
export default function h(sel, data, c) {
    if (arguments.length !== 3) {
        throw new Error('argument error')
    }
    // 检查参数c的类型
    if(typeof c === 'string' || typeof c === 'number') {
        // 说明是形态 h(sel, {}, text)
        return vnode(sel, data, undefined, c, undefined)
    } else if (Array.isArray(c)) {
        // 说明是形态 h(sel, {}, Array<Vnode>)
        // 循环遍历,确保每个子节点都是正确的格式
        for(let i = 0; i < c.length; i++) {
            if (!(typeof c[i] === 'object' && c[i].hasOwnProperty('sel'))) {
                throw new Error('argument type error')
            }
        }
        return vnode(sel, data, c, undefined, undefined)
    } else if (typeof c === 'object' && c.hasOwnProperty('sel')) {
        // 说明是形态 h(sel, {}, vnode) 传入的c是唯一的children
        return vnode(sel, data, c, undefined, undefined)
    } else {
        throw new Error('argument type error')
    }
}

三、createElement

createElement是一个函数,功能是将生成的虚拟节点转化为真实DOM, 并将虚拟节点的vnode的elm指向该生成的DOM。

// createElement.js-递归调用
export default function createElement(vnode) {
    let domNode = document.createElement(vnode.sel)
    if (vnode.text && (!vnode.children || vnode.children === 0)) {
        // h(sel, {}, text)形式生成的vnode
        // domNode的子节点是文本,直接将文本挂载到真实的DOM上
        domNode.innerText = vnode.text
    } else if (vnode.children && !Array.isArray(vnode.children)) {
        // h(sel, {}, vnode)形式生成的vnode
        // domNode的子节点是一个虚拟节点,需要调用createElement自身生成真实DOM,并将真实DOM挂载到domNode上
        let chDOM = createElement(vnode.children)
        domNode.appendChild(chDOM)
    } else if (Array.isArray(vnode.children) && vnode.children.length > 0) {
        // h(sel, {}, Array<vnode>)形式生成的vnode
        // domNode的每个子节点都是虚拟节点,需要循环调用createElement自身生成真实DOM,并以此挂载到domNode上
        for(let i = 0; i < vnode.children.length; i++) {
            let chVnode = vnode.children[i]
            let chDOM = createElement(chVnode)
            domNode.appendChild(chDOM)
        }
    }
    // 將vnode的elm指向真实DOM
    vnode.elm = domNode
    return vnode.elm
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值