前言
上一篇《关于Virtual Dom的那些事(二)》主要是介绍了VNode。其实生成VNode的方式在snabbdom中除了VNode自身的最基本的构造函数vnode()外,还有两种方式来生成。一种是toVNode(即把原生的Dom转化成为VNode),还有一种是非常有名的h函数(hyperscript最原始的定义是“Create HyperText with JavaScript.”)。本节主要是分析一下这两种函数在snabbdom中的源码。
toVNode函数的源码
1 | import vnode, {VNode} from './vnode' ; |
2 | import htmlDomApi, {DOMAPI} from './htmldomapi' ; |
4 | export function toVNode(node: Node, domApi?: DOMAPI): VNode { |
5 | const api: DOMAPI = domApi !== undefined ? domApi : htmlDomApi; |
7 | if (api.isElement(node)) { |
8 | const id = node.id ? '#' + node.id : '' ; |
9 | const cn = node.getAttribute( 'class' ); |
10 | const c = cn ? '.' + cn.split( ' ' ).join( '.' ) : '' ; |
11 | const sel = api.tagName(node).toLowerCase() + id + c; |
12 | const attrs: any = {}; |
13 | const children: Array<VNode> = []; |
15 | let i: number, n: number; |
16 | const elmAttrs = node.attributes; |
17 | const elmChildren = node.childNodes; |
18 | for (i = 0, n = elmAttrs.length; i < n; i++) { |
19 | name = elmAttrs[i].nodeName; |
20 | if (name !== 'id' && name !== 'class' ) { |
21 | attrs[name] = elmAttrs[i].nodeValue; |
24 | for (i = 0, n = elmChildren.length; i < n; i++) { |
25 | children.push(toVNode(elmChildren[i], domApi)); |
27 | return vnode(sel, {attrs}, children, undefined, node); |
28 | } else if (api.isText(node)) { |
29 | text = api.getTextContent(node) as string; |
30 | return vnode(undefined, undefined, undefined, text, node); |
31 | } else if (api.isComment(node)) { |
32 | text = api.getTextContent(node) as string; |
33 | return vnode( '!' , {}, [], text, node as any); |
35 | return vnode( '' , {}, [], undefined, node as any); |
39 | export default toVNode; |
h函数的源码
其实h函数(即hyperscript,最原始的定义是“Create HyperText with JavaScript.”)的应用非常广泛,各种Virtual Dom的实现方式都看到h函数的身影。最热的两个前端框架React及Vue框架都直接支持在其jsx或者.vue文件的template里面使用h函数来定义dom结构。其表现方式非常直接,如:h(sel, data, children),而children也可以递归表示为h函数,那么,还可以这么表示:h(sel, data [h(sel1, data1, children1),h(sel2, data2, children2),…]支持更多层递归表示。使用h函数来表示或者生成虚拟节点相对于VNode的接口定义更为简洁,因为它只接受最多3个参数,然后可以支持无限嵌套。
总而言之
我们可以使用toVNode函数把现有的dom树结构转化成为OldVNode(这种方式特别适用于服务器端渲染的情况,一些框架如果想实现服务器端渲染,渲染后则需把其生成的Dom转化成为VNode,此时就可以使用此方式来进行渲染),后面如果输入的数据有变化可以使用h函数结合数据创建NewVNode(h函数也是推荐使用且最常用的生成VNode的方式),然后通过snabbdom的patch方法对旧VNode与新VNode通过diff算法进行比较然后进行局部更新dom节点,而不需要重新渲染整棵dom树,这就是Virtual Dom的工作原理。
阅读:
5,704
作者: 博主
Talk is cheap, show me the code!
查看博主的所有文章
好文章!666,学习了
多谢