前言
上一篇《关于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来组织各种属性、事件等等,更加井井有序和合理。