欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue 虚拟DOM快速入门

程序员文章站 2022-03-19 14:55:15
虚拟 dom什么是虚拟 domdom 是文档对象模型,以节点树的形式来表现文档。虚拟 dom 不是真正意义上的 dom。而是一个 javascript 对象。正常的 dom 节点在 html 中是这样...

虚拟 dom

什么是虚拟 dom

dom 是文档对象模型,以节点树的形式来表现文档。

虚拟 dom 不是真正意义上的 dom。而是一个 javascript 对象。

正常的 dom 节点在 html 中是这样表示:

而在虚拟 dom 中大概是这样:

我们可以将虚拟 dom 拆分成两部分进行理解:虚拟 + dom。

  • 虚拟: 表示虚拟 dom 不是真正意义上的 dom,而是一个 javascript 对象;
  • dom: 表示虚拟 dom 能以类似节点树的形式表示文档。

虚拟 dom 的作用

现在主流的框架都是声明式操作 dom 的框架。我们只需要描述状态与 dom 之间的映射关系即可,状态到视图(真实的 dom)的转换,框架会帮我们做。

最粗暴的做法是将状态渲染成视图,每次更新状态,都重新更新整个视图。

这种做法的性能可想而知。比较好的想法是:状态改变,只更新与状态相关的 dom 节点。虚拟 dom 只是实现这个想法的其中一种方法而已。

具体做法:

  • 状态 -> 真实 dom(最初)
  • 状态 -> 虚拟 dom -> 真实 dom(使用虚拟 dom)

状态改变,重新生成一份虚拟 dom,将上一份和这一份虚拟 dom 进行对比,找出需要更新的部分,更新真实 dom。

vue 中的虚拟 dom

真实的 dom 是由 节点(node)组成,虚拟 dom 则是由虚拟节点(vnode)组成。

虚拟 dom 在 vue 中主要做两件事:

  • 提供与真实节点(node)对应的虚拟节点(vnode)
  • 将新的虚拟节点与旧的虚拟节点进行对比,找出需要差异,然后更新视图

“虚拟 dom”是我们对由 vue 组件树建立起来的整个 vnode 树的称呼 —— vue 官网

vnode

什么是 vnode

上文提到,vnode(虚拟节点)对应的是真实节点(node)。

vnode 可以理解成节点描述对象。描述了如何创建真实的 dom 节点。

vue.js 中有一个 vnode 类。可以使用它创建不同类型的 vnode 实例,不同类型的 vnode 对应着不同类型的 dom 元素。代码如下:

从代码不难看出 vnode 类创建的实例,本质上就是一个普通的 javascript 对象。

vnode 的类型

前面我们已经介绍通过 vnode 类可以创建不同类型的 vnode。而不同类型的 vnode 是由有效属性区分。例如 iscomment = true 表示注释节点;iscloned = true 表示克隆节点等等。

vnode 类型有:注释节点、文本节点、克隆节点、元素节点、组件节点。

以下是注释节点、文本节点和克隆节点的代码:

克隆节点其实就是将现有节点的所有属性赋值到新节点中,最后用 cloned.iscloned = true 标记自身是克隆节点。

元素节点通常有以下 4 个属性:

  • tag:节点名称。例如 div、p
  • data:节点上的数据。例如 class、style
  • children:子节点
  • context:在组件内呈现

组件节点与元素节点类似,包含两个独有的属性:

  • componentoptions:组件节点的选项参数,例如propsdata、listeners、children、tag
  • componentinstance:组件的实例

patch

前面已经介绍了虚拟 dom 在 vue 中做的第一件事:提供与真实节点(node)对应的虚拟节点(vnode);接下来介绍第二件事:将新的虚拟节点与旧的虚拟节点进行对比,找出需要差异,然后更新视图。

第二件事在 vue 中的实现叫做 patch,即打补丁、修补的意思。通过对比新旧 vnode,找出差异,然后在现有 dom 的基础上进行修补,从而实现视图更新。

对比 vnode 找差异是手段,更新视图才是目的。

而更新视图无非就是新增节点、删除节点和更新节点。接下来我们逐一分析什么时候新增节点、在哪里新增;什么时候删除节点,删除哪个;什么时候更新节点,更新哪个;

注:当 vnode 与 oldvnode 不相同的时候,以 vnode 为准。

新增节点

一种情况是:vnode 存在而 oldvnode 不存在时,需要新增节点。最典型的是初次渲染,因为 odlvnode 是不存在的。

另一种情况是 vnode 与 oldvnode 完全不是同一个节点。这时就需要使用 vnode 生成真实的 dom 节点并插入到 oldvnode 指向的真实 dom 节点旁边。oldvnode 则是一个被废弃的节点。例如下面这种情况:

当 type 由 a 变为 b,节点就会从 p 变成 span,由于 vnode 与 oldvnode 完全不是同一个节点,所以需要新增节点。

删除节点

当节点只在 oldvnode 中存在时,直接将其删除即可。

更新节点

前面介绍了新增节点和删除节点的场景,发现它们有一个共同点:vnode 与 oldvnode 完全不相同。

但更常见的场景是 vnode 与 oldvnode 是同一个节点。然后我们需要对它们(vnode 与 oldvnode)进行一个更细致的对比,再对 oldvnode 对应的真实节点进行更新。

对于文本节点,逻辑自然简单。首先对比新旧 vnode,发现是同一个节点,然后将 oldvnode 对应的 dom 节点的文本改成 vnode 中的文本即可。但对于复杂的 vnode,比如界面中的一颗树组件,这个过程就会变得复杂。

新增节点 - 源码分析

思考一下:前面说到 vnode 的类型有:注释节点、文本节点、克隆节点、元素节点、组件节点。请问这几种类型都会被创建并插入到 dom 中吗?

答:只有注释节点、文本节点、元素节点。因为 html 只认识这几种。

由于只有上面三种节点类型,根据类型做响应的创建,然后插入对应的位置即可。

以元素节点为例,如果 vnode 有 tag 属性,则说明是元素节点。则调用 createelement 方法创建对应的节点,接下来就通过 appendchild 方法插入到指定父节点中。如果父元素已经在视图中,那么把元素插入到它下面将会自动渲染出来;如果 vnode 的 iscomment 属性是 true,则表示注释节点;都不是则是文本节点;

通常元素里面会有子节点,所以这里涉及一个递归的过程,也就是将 vnode 中的 children 依次遍历,创建节点,然后插入到父节点(父节点也就是刚刚创建出的 dom 节点)中,一层一层的递归进行。

请看源码:

删除节点 - 源码分析

删除节点非常简单。直接看源码:

以上就是vue 虚拟dom快速入门的详细内容,更多关于vue 虚拟dom的资料请关注其它相关文章!

相关标签: vue 虚拟DOM