蓝狮注册开户一文带你掌握虚拟 DOM 的灵魂

概述
react 和 vue 中都有虚拟 dom,我们应该如何理解和掌握虚拟 DOM 的精髓呢?我推荐大家学习Snabbdom 这个项目。Snabbdom 是一个虚拟 DOM 实现库,推荐的原因一是代码比较少,核心代码只有几百行;二是 Vue 就是借鉴此项目的思路来实现虚拟 DOM 的;三是这个项目的设计/实现和扩展思路值得参考。

snabb /snab/,瑞典语,意思是快速的。

调整好舒服的坐姿,打起精神我们要开始啦~ 要学习虚拟 DOM,我们得先知道 DOM 的基础知识和用 JS 直接操作 DOM 的痛点在哪里。

DOM 的作用和类型结构
DOM(Document Object Model)是一种文档对象模型,用一个对象树的结构来表示一个 html/XML 文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象。DOM api 的方法让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。

DOM 树中的所有节点首先都是一个 Node , Node 是一个基类。 Element , Text 和 Comment 都继承于它。

换句话说, Element , Text 和 Comment 是三种特殊的 Node ,它们分别叫做 ELEMENT_NODE ,

TEXT_NODE 和 COMMENT_NODE ,蓝狮注册代表的是元素节点(HTML 标签)、文本节点和注释节点。其中 Element 还有一个子类是 HTMLElement ,那 HTMLElement 和 Element 有什么区别呢? HTMLElement 代表 HTML 中的元素,如: 、 等,而有些元素并不是 HTML 标准的,比如 。可以用下面的方法来判断这个元素是不是 HTMLElement :

document.getElementById(‘myIMG’) instanceof HTMLElement;
为什么需要虚拟 DOM?
浏览器创建 DOM 是很“昂贵”的。来一个经典示例,我们可以通过 document.createElement(‘div’) 创建一个简单的 div 元素,将属性都打印出来康康:

可以看到打印出来的属性非常多,当频繁地去更新复杂的 DOM 树时,会产生性能问题。虚拟 DOM 就是用一个原生的 JS 对象去描述一个 DOM 节点,所以创建一个 JS 对象比创建一个 DOM 对象的代价要小很多。

VNode
Vnode 就是 Snabbdom 中描述虚拟 DOM 的一个对象结构,内容如下:

type Key = string | number | symbol;

interface VNode {
// css 选择器,比如:’div#container’。
sel: string | undefined;

// 通过 modules 操作 CSS classes、attributes 等。
data: VNodeData | undefined;

// 虚拟子节点数组,数组元素也可以是 string。
children: Array | undefined;

// 指向创建的真实 DOM 对象。
elm: Node | undefined;

/**

  • text 属性有两种情况:
  • 1. 没有设置 sel 选择器,说明这个节点本身是一个文本节点。
  • 2. 设置了 sel,说明这个节点的内容是一个文本节点。
    */
    text: string | undefined; // 用于给已存在的 DOM 提供标识,蓝狮注册开户在同级元素之间必须唯一,有效避免不必要地重建操作。
    key: Key | undefined;
    }

// vnode.data 上的一些设置,class 或者生命周期函数钩子等等。
interface VNodeData {
props?: Props;
attrs?: Attrs;
class?: Classes;
style?: VNodeStyle;
dataset?: Dataset;
on?: On;
attachData?: AttachData;
hook?: Hooks;
key?: Key;
ns?: string; // for SVGs
fn?: () => VNode; // for thunks
args?: any[]; // for thunks
is?: string; // for custom elements v1
[key: string]: any; // for any other 3rd party module
}
例如这样定义一个 vnode 的对象:

const vnode = h(
‘div#container’,
{ class: { active: true } },
[
h(‘span’, { style: { fontWeight: ‘bold’ } }, ‘This is bold’),
‘ and this is just normal text’
]);
我们通过 h(sel, b, c) 函数来创建 vnode 对象。 h() 代码实现中主要是判断了 b 和 c 参数是否存在,并处理成 data 和 children,children 最终会是数组的形式。最后通过 vnode() 函数返回上面定义的 VNode 类型格式。

0 Comments
Leave a Reply