相信使用过vue的朋友都对这个h函数不陌生了,在vue中是通过调用 h 函数来生成虚拟DOM,今天就来简单实现一下这个 h 函数的功能。
目录结构
安装的依赖。这里的snabbdom依赖很重要,它是实现Virtual DOM的一种。
然后就是webpack的配置了
在vnode.js文件中把传入的5个参数组合成对象再返回。
在这里调用h函数时会有三种形态,前两个参数都是一样的,第一个就是结点的便签名了,第二个参数就是一个对象,用来保存ID名、类名的,第三个参数是用来保存数据的,比如文字、数组或者在这个标签是否有子元素,有的话也会在调用一次h函数进行递归并且保存在这里面。
接下来看代码
import vnode from './vnode.js'
// 调用时的形态:
// 1、h('div', {}, '文字')
// 2、h('div', {}, [])
// 3、h('div', {}, h())
export default function(sel, data, c) {
// 检查参数的个数
if (arguments.length != 3) {
throw new Error('对不起,h必须传入3个参数')
}
// 检查参数 c 的类型
if (typeof c == 'string' || typeof c == 'number') {
// 调用形态 1
return vnode(sel, data, undefined, c, undefined)
} else if (Array.isArray(c)) {
// 调用形态 2
let children = [];
// 遍历 c 收集children
for(let i = 0; i < c.length; i++) {
// 检查从c[i]必须是一个对象 如果不满足
if (!(typeof c[i] == 'object' && c[i].hasOwnProperty('sel'))) {
throw new Error('传入的数组中有项的结果不是h函数')
}
// 收集c[i]
children.push(c[i])
}
// 循环结束 说明children收集结束
return vnode(sel, data, children, undefined, undefined)
} else if (typeof c == 'object' && c.hasOwnProperty('sel')) {
// 调用形态3
let children = [c]
return vnode(sel, data, children, undefined, undefined)
} else {
throw new Error('传入的第三个参数类型错误')
}
}
,首先是暴露一个方法出去,并且这个方法需要传入三个参数,就是上面说的三个。进到这个函数中来,一开始就是需要判断参数是否符合三个,不符合则抛出异常
然后就是判断第三个参数c的类型了,当传入的是string、number类型的数据时,则调用第一种形态,h(‘div’, {}, ‘文字’)。
将children、elm参数设置为undefined并返回
然后就是调用形态二了,首先要判断是否为一个数组,然后呢因为传入的是数组,这个时候就需要用到遍历了
这里需要声明一个children变量,然后遍历传入的 c 参数,还需要判断里面的每个元素是否为对象,并且还要求它拥有 “sel” 属性,也就是标签名,不符合则抛出错误,符合则将其收集到children变量中,当循环结束时说明children收集结束,然后将其返回出去。
形态三跟形态二实际上是差不多的,只不过形态二是调用多个 h 函数,也就是里面有多个子元素,而形态三只调用一次 h 函数即一个元素。