From 74f8b98509d24487e1a8d1588b4128a7a1046a41 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 26 Jul 2016 15:49:40 -0400 Subject: [PATCH] handle static vnodes properly during patch (fix #3325) --- src/core/instance/render.js | 11 ++++++---- src/core/vdom/patch.js | 11 ++++++++-- src/core/vdom/vnode.js | 2 ++ test/unit/modules/vdom/patch/children.spec.js | 20 +++++++++++++++++++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/core/instance/render.js b/src/core/instance/render.js index 9258af95..2e9c517d 100644 --- a/src/core/instance/render.js +++ b/src/core/instance/render.js @@ -103,13 +103,16 @@ export function renderMixin (Vue: Class) { // number conversion Vue.prototype._n = toNumber - // + // render static tree by index Vue.prototype._m = function renderStatic (index?: number): Object | void { - return this._staticTrees[index] || ( - this._staticTrees[index] = this.$options.staticRenderFns[index].call( + let tree = this._staticTrees[index] + if (!tree) { + tree = this._staticTrees[index] = this.$options.staticRenderFns[index].call( this._renderProxy ) - ) + tree.isStatic = true + } + return tree } // filter resolution helper diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index 37386700..f531f84d 100644 --- a/src/core/vdom/patch.js +++ b/src/core/vdom/patch.js @@ -24,6 +24,9 @@ function isDef (s) { } function sameVnode (vnode1, vnode2) { + if (vnode1.isStatic || vnode2.isStatic) { + return vnode1 === vnode2 + } return ( vnode1.key === vnode2.key && vnode1.tag === vnode2.tag && @@ -259,8 +262,12 @@ export function createPatchFunction (backend) { newStartVnode = newCh[++newStartIdx] } else { if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) - idxInOld = oldKeyToIdx[newStartVnode.key] - if (isUndef(idxInOld)) { // New element + idxInOld = isDef(newStartVnode.key) + ? oldKeyToIdx[newStartVnode.key] + : newStartVnode.isStatic + ? oldCh.indexOf(newStartVnode) + : null + if (isUndef(idxInOld) || idxInOld === -1) { // New element nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm) newStartVnode = newCh[++newStartIdx] } else { diff --git a/src/core/vdom/vnode.js b/src/core/vdom/vnode.js index c44411b1..0f75722f 100644 --- a/src/core/vdom/vnode.js +++ b/src/core/vdom/vnode.js @@ -14,6 +14,7 @@ export default class VNode { child: Component | void; parent: VNode | void; raw: ?boolean; + isStatic: ?boolean; constructor ( tag?: string, @@ -39,6 +40,7 @@ export default class VNode { this.child = undefined this.parent = undefined this.raw = false + this.isStatic = false // apply construct hook. // this is applied during render, before patch happens. // unlike other hooks, this is applied on both client and server. diff --git a/test/unit/modules/vdom/patch/children.spec.js b/test/unit/modules/vdom/patch/children.spec.js index c8cb4375..1e6be74e 100644 --- a/test/unit/modules/vdom/patch/children.spec.js +++ b/test/unit/modules/vdom/patch/children.spec.js @@ -466,4 +466,24 @@ describe('children', () => { expect(child1).not.toBe(child2) expect(child2.className).toBe('') }) + + it('should handle static vnodes properly', function () { + function makeNode (text) { + return new VNode('div', undefined, [ + new VNode(undefined, undefined, undefined, text) + ]) + } + const b = makeNode('B') + b.isStatic = true + const vnode1 = new VNode('div', {}, [makeNode('A'), b, makeNode('C')]) + const vnode2 = new VNode('div', {}, [b]) + const vnode3 = new VNode('div', {}, [makeNode('A'), b, makeNode('C')]) + + let elm = patch(vnode0, vnode1) + expect(elm.textContent).toBe('ABC') + elm = patch(vnode1, vnode2) + expect(elm.textContent).toBe('B') + elm = patch(vnode2, vnode3) + expect(elm.textContent).toBe('ABC') + }) })