什么是虚拟DOM
一个表示Dom树的JS对象,这个对象通常由标签名,子元素,属性,事件监听组成
使用虚拟DOM的优点
减少DOM操作的次数
- 比如虚拟DOM可以将1000次添加一个div合并为一次添加1000个div
减少DOM操作的范围
- 提前通过diff算法的比对,对比改动前后的dom节点变化,只影响真正发生变化的的DOM节点
可以跨平台渲染,因为本质是JS对象,可以变成DOM树也可以变成IOS树和安卓上的树
使用虚拟DOM的缺点
- 因为用到了模板语法(Vue模板或者是React的JSX语法)而非原生的JS,导致严重依赖打包工具将模板语法转译成JS
虚拟DOM长什么样
React vNode
Vue vNode
如何在React Vue中手动创建虚拟DOM?
- React中的
createElement函数 - Vue中的render函数中的
h函数
React用JSX语法简化手动调用createElement函数创建虚拟DOM的流程
JSX 通过babel转译成createElement函数 => 真实DOM
Vue的template类似JSX也是用于简化手动调用h函数创建虚拟DOM的流程
Vue template 通过vue-loader转译成h函数 => 真实DOM
原生DOM与虚拟DOM的实际对比
真实结论是如果DOM节点数比较少的时候绝对是虚拟DOM快,但是当DOM节点数到了10W的时候就是原生DOM快
什么是DOM diff?
diff是一个叫patch的函数,这个函数内部有一套逻辑用以层层比对新旧dom然后选择删除节点还是更新节点,这个函数会返回一个对象,这个对象如下,包含着一系列关于如何操作DOM的信息
DOM diff 的优点
DOM diff算法可以排除多余的DOM操作。DOM diff会对比前后两次DOM树的区别,然后只更新有变化的DOM节点,优化操作。
DOM diff 的缺点即 key的作用
同级比较会出现bug。diff算法是从左往右进行同层级对比的,如果发现元素相同但是内容不相同,会直接修改内容。这会导致有时删除了一个节点,结果却是另外一个节点被删除了。这个问题可以通过给每一个列表指定key值来解决,注意这里的key值不能指定为index,否则无效。
如果不加key,则没有下标的概念
[1,2,3]这样的数组对于计算机而言是[0:1,1:2,2:3]如果删除中间项2,则计算机会认为结果是[0:1,1:3]电脑通过比对会认为当中项并没有被删除,只是更改了值,而被删除的是最后项
如果加了key,计算机才会认识下标,并且认为特定的下标与节点是捆绑在一起的
[0:1,1:2,2:3]===>[0:1,2:3]
一个重要的例子理解key的作用
- 修改中间项内容并且点击按钮所触发的操作是: 去往data中删除数组的中间项,
- 那么请问删除了中间项以后,data的变化是否如上图所示?没错吧
- 数据发生了变化以后,则vue再次v-for的时候会根据修改后的数组重新渲染,
- 由于没有子组件身上绑定key,因此vue认为你数组长度从3变成了2,那我把最后一个子组件删除掉不就好了吗
- 但如果子组件身上绑定了唯一性的key,那么vue就知道了子组件节点是和data中的数组内容是一一绑定的
- 比如数组项内容2绑着第二个子组件,删2就是删第二个子组件节点
为什么不能用v-for中自带的index 作为 key?
因为这个index其实跟你数组中隐含的下标是一回事,并没有一一对应的唯一性,你删掉内容中的中间项,作为下标,它依然存在下标1