Vue学习手册03 Vue虚拟DOM详解
底层的虚拟DOM
Vue doesn’t work directly with the Document Object Model (DOM). Instead, it implements its Virtual DOM to optimize the application’s performance on run-time.
Vue不直接使用文档对象模型(DOM)。相反,它实现了Virtual DOM来优化应用程序在运行时的性能。
To build a solid understanding of how Virtual DOM works, we start with the concept of the DOM.
为了牢固地理解Virtual DOM的工作原理,我们从DOM的概念开始。
The DOM represents the HTML (or XML) document content on the web, in the form of an in-memory tree-like data structure (as shown in Figure 2-1). It acts as a programming interface that connects the web page and the actual programming code (such as JavaScript). Tags, such as <div>
or <section>
, in the HTML document are represented as programmatic nodes and objects.
DOM表示web上的HTML(或XML)文档内容,以内存中的树状数据结构的形式呈现(如图2-1所示)。它作为连接网页和实际编程代码(如JavaScript)的编程接口。HTML文档中的标记(如<div>
或<section>
)表示为可编程节点和对象。
After the browser parses the HTML document, the DOM will be available for interaction immediately. Upon any layout changes, the browser then paints and repaints the DOM constantly in the background. We call the process parsing, and painting the DOM screen rasterization or the pixel-to-screen pipeline. Figure 2-2 demonstrates how rasterization works:
在浏览器解析HTML文档之后,DOM将立即用于交互。一旦布局发生变化,浏览器就会在后台不断地绘制和重新绘制DOM。我们将此过程称为解析,并绘制DOM屏幕光栅化或像素到屏幕管道。图2-2演示了光栅化的工作原理:
布局更新问题
Each paint is costly to the browser’s performance. Since the DOM may consist of many nodes, querying and updating single or multiple nodes can be extremely expensive.
每次油漆对浏览器的性能都是昂贵的。由于DOM可能由许多节点组成,因此查询和更新单个或多个节点的成本可能非常高。
Here is a simple example of a list of li elements in the DOM:
下面是DOM中li元素列表的一个简单示例:
<ul class="list" id="todo-list">
<li class="list-item">To do item 1</li>
<li class="list-item">To do item 2</li>
<!--so on…-->
</ul>
Adding/removing a li element or modifying its content requires querying the DOM for that item using document.getElementById (or document.getElementsByClass Name). Then you need to perform the desired updates using the appropriate DOM APIs.
添加/删除li元素或修改其内容需要使用document.getElementById查询该项的DOM(或document.getElementsByClass名称)。然后需要使用适当的DOM api执行所需的更新。
For instance, if you want to add a new item to the previous example, you need to do the following steps:
-
Query the containing list element by its id attribute’s value—“todo-list”
-
Add the new li element using document.createElement()
-
Set the textContent and the relevant attributes to match other element’s standard using setAttribute().
-
Append that element to the list element found in step 1 as its child using appendChild():
例如,如果您想在前面的示例中添加一个新项,您需要执行以下步骤:
-
查询包含列表元素的id属性值- “todo-list”
-
使用document.createElement()添加新的li元素
-
使用setAttribute()设置textContent和相关属性以匹配其他元素的标准。
-
使用appendChild()将该元素添加到步骤1中找到的列表元素中,作为其子元素:
const list = document.getElementById('todo-list');
const newItem = document.createElement('li');
newItem.setAttribute('class', 'list-item');
newItem.textContent = 'To do item 3';
list.appendChild(newItem);
Similarly, suppose you want to change the text content of the 2nd li item to “buy groceries”. In that case, you perform step 1 to get the containing list element, then query the target element using getElementsByClassName(), and finally change its textContent to the new content:
类似地,假设您想将第二个li项的文本内容更改为“buy grocery”。在这种情况下,执行步骤1获取包含列表元素,然后使用getElementsByClassName()查询目标元素,最后将其textContent更改为新内容:
const secondItem = list.getElementsByClassName('list-item')[1];
secondItem.textContent = 'Buy groceries'
Querying and updating the DOM on a small scale usually do not enormously impact performance. However, these actions can slow the page if performed more repetitively (within a few seconds) and on a more complex web page. The performance impact is significant when there are consecutive minor updates. Many frameworks, such as Angular 1.x, fail to acknowledge and address this performance issue as the codebase grows. The Virtual DOM is designed to solve the layout update problem.
小规模地查询和更新DOM通常不会对性能产生巨大影响。但是,如果在更复杂的网页上重复执行这些操作(在几秒钟内),这些操作可能会减慢页面速度。当有连续的小更新时,性能影响是显著的。很多框架,比如Angular 1.x。随着代码库的增长,未能认识到并解决这个性能问题。虚拟DOM是为了解决布局更新问题而设计的。
什么是虚拟DOM
Virtual DOM is the in-memory virtual copy version of the actual DOM in the browser, but it is lighter weight and has extra functionalities. It mimics the real DOM structure, with a different data structure (usually Object) (see Figure 2-3).
虚拟DOM是浏览器中实际DOM的内存虚拟副本版本,但它的重量更轻,并且具有额外的功能。它模仿真实的DOM结构,使用不同的数据结构(通常是Object)(见图2-3)。
Behind the scenes, the Virtual DOM still uses the DOM API to construct and render updated elements in the browser. Thus, it still causes the browser’s repainting process, but more efficiently.
在幕后,Virtual DOM仍然使用DOM API在浏览器中构造和呈现更新的元素。因此,它仍然会引起浏览器的重新绘制过程,但更有效。
In short, Virtual DOM is an abstract pattern aiming to free the DOM from all the actions that can lead to performance inefficiencies, such as manipulating attributes, handling events, and manually updating DOM elements.
简而言之,Virtual DOM是一种抽象模式,旨在将DOM从可能导致性能低下的所有操作(如操作属性、处理事件和手动更新DOM元素)中解放出来。
虚拟DOM在Vue中如何工作
The Virtual DOM sits between the real DOM and the Vue application code. The following is an example of what a node in the Virtual DOM looks like:
虚拟DOM位于真实DOM和Vue应用程序代码之间。以下是虚拟DOM中节点的示例:
const node = {
tag: 'div',
attributes: [{ id: 'list-container', class: 'list-container' }],
children: [ /* an array of nodes */]
}
Let’s call this node VNode. VNode is a virtual node that resides within the Virtual DOM and represents the actual DOM element in the real DOM.
我们称这个节点为VNode。VNode是驻留在virtual DOM中的虚拟节点,它代表了真实DOM中的实际DOM元素。
Through UI interactions, the user tells Vue what state they wish the element to be in; Vue then triggers the Virtual DOM to update that element’s represented object (node) to the desired shape while keeping track of those changes. Finally, it communicates with the actual DOM and performs accurate updates on the changed nodes accordingly.
通过UI交互,用户告诉Vue他们希望元素处于什么状态;然后,Vue触发Virtual DOM将该元素所表示的对象(节点)更新为所需的形状,同时跟踪这些更改。最后,它与实际的DOM通信,并相应地对更改的节点执行准确的更新。
Since the Virtual DOM is a tree of custom JavaScript objects, updating a component equals updating a custom JavaScript object. This process doesn’t take long. Because we don’t call any DOM API, this update action doesn’t cause a DOM repainting.
由于Virtual DOM是一个自定义JavaScript对象树,更新一个组件就等于更新一个自定义JavaScript对象。这个过程不会花很长时间。因为我们不调用任何DOM API,所以这个更新操作不会导致DOM重新绘制。
Once the Virtual DOM finishes updating itself, it syncs in batch with the actual DOM, leading the changes to be reflected on the browser.
一旦虚拟DOM完成自身更新,它就会与实际DOM批量同步,从而使更改反映在浏览器上。
Figure 2-4 illustrates how updates from the Virtual DOM to the actual DOM work when adding a new list item and changing the list item’s text.
图2-4说明了在添加新列表项和更改列表项的文本时,从Virtual DOM到实际DOM的更新是如何工作的。
Since the Virtual DOM is a tree of objects, we can easily track the specific updates that need to be synced with the actual DOM when modifying the Virtual DOM. Instead of querying and updating directly on the actual DOM, we can now schedule and call the updated APIs with a single render function in one update cycle to maintain performance efficiency.
由于Virtual DOM是一个对象树,因此在修改Virtual DOM时,我们可以很容易地跟踪需要与实际DOM同步的特定更新。与直接在实际DOM上查询和更新不同,我们现在可以在一个更新周期内使用单个呈现函数调度和调用更新后的api,以保持性能效率。
Now that we understand how Virtual DOM works, we will explore the Vue instance and the Vue Options API.
了解了Virtual DOM的工作原理之后,我们将探索Vue实例和Vue Options API。