- 虚拟dom
- 虚拟dom是什么?
- 虚拟dom在vue中做了什么?
- vue 渲染两条线
- 虚拟dom是如何提升vue的渲染效率的?
- 局部更新节点数据
- 将直接操作dom的地方拿到两个js对象之中去做比较
- 虚拟dom生成三要素
- 节点类型/目标元素 [必须有]
- 节点属性
- 子节点
- Diff中的patch
虚拟dom
虚拟dom是什么?
- a.vue2x 才有虚拟dom
- b.本质 js对象 =>跨平台
虚拟dom在vue中做了什么?
vue 渲染两条线
- 1.首次渲染:将真实dom转化虚拟dom (js对象)
- 2.后续更新:更新的时候做对比
vue的渲染过程 (htm1,css,js)
<template>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</template>
虚拟dom是如何提升vue的渲染效率的?
vue 特点
- 组件化
- 数据去驱动
局部更新(节点数据)
将直接操作dom的地方拿到两个js对象之中去做比较
虚拟dom生成三要素
虚拟 DOM (Virtual DOM) 是一种编程概念,它是在用户界面更新过程中用于跟踪和最小化必要的更改的技术。
节点类型/目标元素 [必须有]
节点属性
子节点
在生成虚拟 DOM 时,以下是三个主要要素:
- 节点类型/目标元素:在虚拟 DOM 中,每个节点都有一个特定的类型。这可能是元素节点(如
<div>
,<span>
等)、文本节点(如文本内容)或组件节点(如自定义组件)。节点类型决定了如何渲染和更新该节点。 - 节点属性:每个节点都有一组属性,这些属性定义了节点的外观和行为。例如,元素节点可能有类名、样式、事件处理器等属性。这些属性在虚拟 DOM 中以键值对的形式存储,可以在不改变底层 DOM 结构的情况下进行修改和更新。
- 子节点:每个节点可能有一个或多个子节点,这些子节点可以是其他元素、文本或组件节点。在虚拟 DOM 中,子节点的顺序和数量都是重要的,因为它们决定了渲染的结果。
让我们通过一个简单的例子来理解这三个要素:
假设我们有一个简单的 HTML 元素——一个包含文本的 <div>
元素。
<div id="myDiv">Hello, World!</div>
在虚拟 DOM 中,这将被表示为一个节点对象,其中包含以下三个要素:
- 节点类型/目标元素:这是一个元素节点,类型为
<div>
。 - 节点属性:该节点有一个
id
属性,值为"myDiv"
。 - 子节点:该节点有一个文本子节点,内容为
"Hello, World!"
。
现在,如果我们想更新这个 <div>
元素的内容,我们不需要直接操作 DOM。相反,我们可以更新虚拟 DOM,然后让库或框架将更改应用到实际的 DOM。例如,我们可以将文本更改为 "Hello, Virtual DOM!"
。在虚拟 DOM 中,这将表现为子节点的更改。
虚拟 DOM 使得我们能够以更加可预测和高效的方式更新用户界面,尤其是在处理复杂的应用程序和频繁的更新时。
Diff中的patch
// 1.初始化 patch(container,vnode)
// 2.更新 update(vnode, newVnode)
// 初始化流程
function createElement(vnode){
let tag = vnode.tag // 目标元素 ul
let attrs = vnode.attrs || {} // 属性
let children = vnode.children || [] // 子节点
if(!tag) {
return null
}
// 1.创建对应的dom
let elem = document .createElement(tag)
// 2.给dom添加属性
let attrName
for(attrName in attrs){
if(attrs.hasOwnProperty(attrName)){
// class
elem.setAttribute(attrName, attrs[attrName])
}
}
// 3.将子元素添加到目标之上
children.forEach((childVnode)=>{
elem.appendChild(createElement(childVnode))
})
return elem
}
// 更新流程
function updateChildren(vnode, newVnode){
let children = vnode.children || [] // 现有节点
let newChildren = newVnode.children || [] // 新节点
children.forEach((childrenVnode, index)=>{ // 循环的每一项
let newChildrenVnode = newChildren[index]
// 第一层没有变化
if(childrenVnode.tag === newChildrenVnode.tag){
// 递归查询子元素 深层次对比 > 递归
updateChildren(childrenVnode,newChildrenVnode)
}else{
// 两者tag不一样
replaceNode(childrenVnode, newChildrenVnode)
}
})
}