关于Virtual Dom的那些事(二)

前言

上一篇《关于Virtual Dom的那些事(一)》在最后之处讲到Virtual Dom 主要涉及的概念。本篇将紧跟着并结合snabbdom的源码来讲讲其中的第一点“VNode”。既然是Virtual Dom,那当然其结构里面的Node节点相应也有VNode的概念。其组织形式按理来说应该与真实的Node节点类似才对。

真实Dom由些什么组成呢?

真实的Dom的节点有Node或者Element。Element继成自Node节点,只是不包括 text node,comment node等等。因此,我们可以把Node节点来与VNode进行对比。下面看看Node的简单结构图:

Node简单结构图
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组织简单结构图如下:

VNode简单组织结构图
VNode简单组织结构图

对比真实的Node与VNode

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

作者: 博主

Talk is cheap, show me the code!

发表评论

电子邮件地址不会被公开。

Captcha Code