虚拟DOM就是一个JS对象,用它来描述真实DOM
demo1: 多次执行dom操作
<body>
<div style="width: 200px; border:1px solid #000;"></div>
<script>
var box = document.querySelector('.box');
var count = 0;
console.time('a')
for (var i = 1; i < 10002; i++) {
count = i
box.innerHTML += count
}
console.timeEnd('a')
</script>
</body>
demo2: 只执行一次dom操作
var box = document.querySelector( '.box' ) ;
var num = “0”
console.time( 'b' )
for ( var i = 1 ; i < 10002 ; i ++ ){
num += i
}
box.innerHTML = num
console.timeEnd( 'b' )
比较运行时间:得到结论
越多的真实dom操作,越损耗性能
操作数据要大大的减少性能损耗,提高渲染效率
第一种更新DOM的方案
1、data数据
2、模板
3、数据 + 模板 结合,生成真实的DOM -> 视图
4、data发生了变化
5、数据 + 模板 结合,生成真实的DOM,替换原始的DOM
缺陷:
1、第一次生成了完整的DOM片段
2、第二次生成了完整的DOM片段
3、第二次的DOM替换第一次的DOM,非常耗费性能
第二种更新DOM的方案
1、data数据
2、模板
3、数据 + 模板 结合, 生成真实的DOM -> 视图
4、data发生变化
5、数据 + 模板 结合,生成真实的DOM,并不直接替换原始的DOM
6、新的DOM(DocumentFragment)和原始的DOM做比对,找差异
7、找出变化 (比如input框发生了变化)
8、只用新的DOM中的input元素,替换掉老的DOM中input元素
缺陷:
虽然DOM只是局部替换,但是在比对时候的计算是比较耗费性能的,因此,性能的提升并不明显
第三种使用虚拟DOM的方案
1、读取data数据
2、读取模板
3、数据 + 模板 生成虚拟DOM(虚拟DOM就是一个JS对象,用它来描述真实DOM)(损耗一点性能)
原本准备生成的真实dom: <div id=“abc”><span> hello world </span></div>
虚拟DOM:['div', {id: 'abc‘}, ['span', '', 'hello world']]
4、用虚拟DOM的结构生成真实的DOM -> 视图显示 (用document.createElement可基于虚拟DOM生成真实DOM)
真实DOM:<div id='abc'><span></span></div>
5、当data发生了变化
6、数据 + 模板 生成新的虚拟DOM:
['div', {id: 'abc'}, ['span', '', 'hi world11111']]
7、比较原始虚拟DOM和新的虚拟DOM的区别(diff算法),比如找到的区别是span中的内容发生了变化(极大提升了性能)
8、将变化的部分生成真实DOM(用createElement可基于虚拟DOM生成真实DOM)
9、将不同部分渲染在页面(直接操作DOM,改变span中的内容)
虚拟DOM优点:1、性能提升了 2、它使得跨端应用得以实现,比如:React Native (RN)
1. 获取数据
2. 根据数据创建VDOM 虚拟DOM就是一个JS对象,用它来描述真实DOM(相当于给对象赋值)
3. 根据VDOM渲染生成真实DOM ( 根据createElement(‘DIV’) )
4. 当数据发生改变后,又会生成新的VDOM
5. 通过 diff 算法 比对 多次生成的 VDOM, 将不同的内容比对出来,然后再进行真实DOM渲染,
一样的内容是不会进行渲染的,这就是VDOM 的 ‘就地复用’ | ‘惰性原则’
key是虚拟dom对象的标识 在更新时key起着极其重要的作用
当状态数据发生变化时,vue会根据【新数据】生成【新的虚拟dom】
随后vue进行【新的虚拟dom】与【旧的虚拟dom】的diff比较 比较规则如下:
a. 如果旧虚拟dom找到了与新虚拟dom相同的key
(1)若旧虚拟dom中内容没变,直接使用之前的真实dom
(2)若旧虚拟dom中内容发生了改变,则生成新的真实dom 随后替换掉页面中的真实dom
b. 如果旧虚拟dom未找到与新虚拟dom相同的key
根据数据创建新的真实dom随后渲染到页面
数据:
[{ id: 1, name: '小李', age: 18 },
{ id: 2, name: '小张', age: 19 }]
初始的虚拟dom
<li key=0>小李------18 <input type="text" /></li>
<li key=1>小张------19 <input type="text" /></li>
更新后的数据
{ id: 3, name: '小王', age: 20 },
{ id: 1, name: '小李', age: 18 },
{ id: 2, name: '小张', age: 19 }
更新数据后的虚拟dom
<li key=0>小王------20 <input type="text" /></li>
<li key=1>小李------18 <input type="text" /></li>
<li key=2>小张------19 <input type="text" /></li>
数据:
[{ id: 1, name: '小李', age: 18 },
{ id: 2, name: '小张', age: 19 }]
初始的虚拟dom
<li key=1>小李------18 <input type="text" /></li>
<li key=2>小张------19 <input type="text" /></li>
更新后的数据
{ id: 3, name: '小王', age: 20 },
{ id: 1, name: '小李', age: 18 },
{ id: 2, name: '小张', age: 19 }
更新数据后的虚拟dom:
<li key=3>小王------20 <input type="text" /></li>
<li key=1>小李------18 <input type="text" /></li>
<li key=2>小张------19 <input type="text" /></li>
key的作用主要是为了高效的更新虚拟DOM, 其原理是vue在数据更新过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个更新过程更加高效,减少DOM操作量,提高性能。
另外,若不设置key还可能在列表更新时引发一些隐蔽的bug。
vue中在使用相同标签名元素的过渡(transition组件)切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
v-for比v-if优先,即每一次都需要遍历整个数组,影响速度。
<div
v-for="(fileMsg,index) in fileMsgList"
:key="fileMsg.id"
v-if="index < 2"
>
<sys-file-layout :fileMsg="fileMsg">sys-file-layout>
div>
以上代码,如果有100条数据,虽然显示两条,但需要遍历100次,因为v-for优先
更好的解决方案: 是用computed先获取符合条件的数据,再进行遍历