虚拟DOM与diff算法
虚拟dom
是将状态映射成视图的总舵解决方案的一种,运作原理是使用状态生成虚拟节点,然后使用虚拟节点渲染视图。
虚拟DOM和真实DOM的区别
virtual DOM是将真实的 DOM 的数据抽取出来,以对象的形式模拟树形结构,diff算法比较的也是virtual DOM
为什么引入虚拟DOM
Vue.js1.0变化侦测粒度太细,会有很多watcher同时观察某些状态,多了一些内存开销和依赖追踪的开销。Vue.js2.0的状态侦测不细化到某个具体节点,而是某个组件,组件内部通过虚拟DOM来渲染视图,就可以大大缩减watcher和依赖的数量。
虚拟dom在vue中所做的事
- 提供与真实DOM节点所对应的虚拟节点vnode
- 将新vnode与旧vnode比对,更新视图
vnode是什么?
Vnode是一个类,可以生成不同的vnode实例,而不同类型的vnode表示不同类型的真实DOM元素。
可以理解为节点描述对象,渲染视图的过程就是创建vnode,然后使用vnode去创建真实的DOM节点,生成的DOM节点可以插入到页面渲染视图。
export default class VNode {
tag: string | void;
data: VNodeData | void;
children: ?Array<VNode>;
text: string | void;
elm: Node | void;
ns: string | void;
context: Component | void; // rendered in this component's scope
key: string | number | void;
componentOptions: VNodeComponentOptions | void;
componentInstance: Component | void; // component instance
parent: VNode | void; // component placeholder node
// strictly internal
raw: boolean; // contains raw HTML? (server only)
isStatic: boolean; // hoisted static node
isRootInsert: boolean; // necessary for enter transition check
isComment: boolean; // empty comment placeholder?
isCloned: boolean; // is a cloned node?
isOnce: boolean; // is a v-once node?
asyncFactory: Function | void; // async component factory function
asyncMeta: Object | void;
isAsyncPlaceholder: boolean;
ssrContext: Object | void;
fnContext: Component | void; // real context vm for functional nodes
fnOptions: ?ComponentOptions; // for SSR caching
devtoolsMeta: ?Object; // used to store functional render context for devtools
fnScopeId: ?string; // functional scope id support
constructor (
tag?: string,
data?: VNodeData,
children?: ?Array<VNode>,
text?: string,
elm?: Node,
context?: Component,
componentOptions?: VNodeComponentOptions,
asyncFactory?: Function
) {
this.tag = tag
this.data = data
this.children = children
this.text = text
this.elm = elm
this.ns = undefined
this.context = context
this.fnContext = undefined
this.fnOptions = undefined
this.fnScopeId = undefined
this.key = data && data.key
this.componentOptions = componentOptions
this.componentInstance = undefined
this.parent = undefined
this.raw = false
this.isStatic = false
this.isRootInsert = true
this.isComment = false
this.isCloned = false
this.isOnce = false
this.asyncFactory = asyncFactory
this.asyncMeta = undefined
this.isAsyncPlaceholder = false
}
get child (): Component | void {
return this.componentInstance
}
}
vnode作用
vnode对组件采用了虚拟DOM来更新视图,属性发生变化的时候,整个组件都要进行重新渲染,但是组件内并不是所有的DOM节点都需要更新。Vue中将vnode进行缓存并将新生成的vnode与上一次缓存的oldvnode进行对比,对需要更新的部分进行DOM操作,这样提高了渲染速度,降低了内存消耗。
vnode类型
vnode有多种类型,本质上是从Vnode类实例化出来的对象,唯一区别是属性不同。
-
注释节点
-
文本节点
-
克隆节点
作用是优化静态节点和插槽节点。
因为静态节点的内容一直不会变,可以使用创建克隆节点的方法将静态节点的vnode克隆一份,使用克隆节点进行渲染,这样就不需要重新执行渲染函数生成新的静态节点的vnode,可以提升一定程度的性能。
-
元素节点
-
组件节点
-
函数式节点
patch函数
diff算法是一种优化手段,将前后两个模块进行差异化对比,修补(更新)差异的过程叫做patch(打补丁)。
也就是,Vue中diff算法过程就是调用名为patch函数。
diff算法原理
1、先同级比较,再比较儿子节点
2、先判断一方有儿子一方没儿子的情况
3、比较都有儿子的情况
4、递归比较子节点
vue3中做了优化,只比较动态节点,略过静态节点,极大的提高了效率。
思考
diff算法时间复杂度?
两棵树进行完全比对diff算法的事件复杂度为O(n),Vue对此进行优化,只考虑同级不考虑跨级,将时间复杂度降低到O(n)。
因为我们在操作页面的时候很少会去跨层级的移动DOM元素,所以Virtual DOM只会对同一个层级的元素进行对比。
Vue 中的 key 到底有什么用?
同一层级的一组节点,他们可以通过唯一的id进行区分。key是每一个vnode的唯一id,依靠key,diff操作可以更加准确,更加快速。
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
在B和C之间加一个F,Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
v-for(:key)绑定index、id、key的区别
使用v-for渲染元素时,使用元素自身的id属性去指定渲染元素的key值有利于单个元素的重新渲染,若采用其他如v-for提供的index, key等值,在改变渲染出来的DOM结构时,会触发所有元素的重新渲染,当数据过大时,可能会造成性能负担。
当我们在使用v-for进行渲染时,尽可能使用渲染元素自身属性的id给渲染的元素绑定一个key值,这样在当前渲染元素的DOM结构发生变化时,能够单独响应该元素而不触发所有元素的渲染。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!