源码:https://github.com/vuejs/vue/blob/dev/src/core/vdom/patch.js
虚拟dom
diff算法首先要明确一个概念就是diff的对象是虚拟dom,更新真实dom则是diff算法的结果
Vnode基类
constructor ( 。。。 ) { 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 }
这个部分的代码 主要是为了更好地知道在diff算法中具体diff的属性的含义,当然也可以更好地了解vnode实例
整体过程
核心函数是patch函数
isUndef判断(是不是undefined或者null) // empty mount (likely as component), create new root elementcreateElm(vnode, insertedVnodeQueue) 这里可以发现创建节点不是一个一个插入,而是放入一个队列中统一批处理function sameVnode (a, b) { return ( a.key === b.key && ( ( a.tag === b.tag && a.isComment === b.isComment && isDef(a.data) === isDef(b.data) && sameInputType(a, b) ) || ( isTrue(a.isAsyncPlaceholder) && a.asyncFactory === b.asyncFactory && isUndef(b.asyncFactory.error) ) ) )}
这里是一个外层的比较函数,直接去比较了两个节点的key,tag(标签),data的比较(注意这里的data指的是VNodeData),input的话直接比较type。
export interface VNodeData { key?: string | number; slot?: string; scopedSlots?: { [key: string]: ScopedSlot }; ref?: string; tag?: string; staticClass?: string; class?: any; staticStyle?: { [key: string]: any }; style?: object[] | object; props?: { [key: string]: any }; attrs?: { [key: string]: any }; domProps?: { [key: string]: any }; hook?: { [key: string]: Function }; on?: { [key: string]: Function | Function[] }; nativeOn?: { [key: string]: Function | Function[] }; transition?: object; show?: boolean; inlineTemplate?: { render: Function; staticRenderFns: Function[]; }; directives?: VNodeDirective[]; keepAlive?: boolean;}
这会确认两个节点是否有进一步比较的价值,不然直接替换
替换的过程主要是一个createElm函数 另外则是销毁oldVNode
// destroy old node if (isDef(parentElm)) { removeVnodes(parentElm, [oldVnode], 0, 0) } else if (isDef(oldVnode.tag)) { invokeDestroyHook(oldVnode) }
新闻热点
疑难解答
图片精选