前言
上一篇《关于Virtual Dom的那些事(一)》在最后之处讲到Virtual Dom 主要涉及的概念。本篇将紧跟着并结合snabbdom的源码来讲讲其中的第一点“VNode”。既然是Virtual Dom,那当然其结构里面的Node节点相应也有VNode的概念。其组织形式按理来说应该与真实的Node节点类似才对。
真实Dom由些什么组成呢?
真实的Dom的节点有Node或者Element。Element继成自Node节点,只是不包括 text node,comment node等等。因此,我们可以把Node节点来与VNode进行对比。下面看看Node的简单结构图:

VNode呢?我们来看看Snabbdom如何对VNode进行抽象?
结合Snabbdom中关于VNode的源码如下:
import {Hooks} from './hooks';
import {AttachData} from './helpers/attachto'
import {VNodeStyle} from './modules/style'
import {On} from './modules/eventlisteners'
import {Attrs} from './modules/attributes'
import {Classes} from './modules/class'
import {Props} from './modules/props'
import {Dataset} from './modules/dataset'
import {Hero} from './modules/hero'
export type Key = string | number;
export interface VNode { // VNode的接口定义。使用typescript的好处就是可以以强语言的方式来先抽象定义好VNode的接口,什么是VNode,由接口的定义就一目了然
sel: string | undefined; // 元素的选择器,可以是tagName、className、Id或者结合组成的元素选择器
data: VNodeData | undefined; // VNode数据,下面有定义
children: Array<VNode | string> | undefined; // 每个VNode可能有子VNode,这跟真实的Node是一样的
elm: Node | undefined; // 其对应的真实的Node
text: string | undefined; // 如果是文本节点就有text
key: Key | undefined; // 可以给节点定义一个key便于检索
}
export interface VNodeData { // VNodeData的接口定义。上面用到的VNodeData里面可能包含东西是什么?
props?: Props; // 如真实Dom中的disabled、selected类属性参数
attrs?: Attrs; // 如value、placeholder等属性
class?: Classes; // 可以定义css样式
style?: VNodeStyle; // 自定义的style
dataset?: Dataset; // data-开头的一性属性
on?: On; // 事件类的绑定函数,如click
hero?: Hero; // 动画效果有关的操作支持
attachData?: AttachData; // 附加的数据
hook?: Hooks; // 给VNode增加一些勾子,在Vnode的生命周期期间会执行相应的勾子函数
key?: Key;
ns?: string; // for SVGs
fn?: () => VNode; // for thunks
args?: Array<any>; // for thunks
[key: string]: any; // for any other 3rd party module
}
export function vnode(sel: string | undefined,
data: any | undefined,
children: Array<VNode | string> | undefined,
text: string | undefined,
elm: Element | Text | undefined): VNode { // VNode的工具函数, 用其可生成一个VNode
let key = data === undefined ? undefined : data.key;
return {sel: sel, data: data, children: children,
text: text, elm: elm, key: key};
}
export default vnode;
VNode组织简单结构图如下:

对比真实的Node与VNode
VNode是有点像一个加强版的Node,比如VNode中的sel相对于真实的Node的tagName,其选择器的能力本来就更加强大、直观和更容易操作。真实的Node节点各种属性组织得比较混乱,而VNode则通过data来组织各种属性、事件等等,更加井井有序和合理。