Skip to content

Commit

Permalink
handle static vnodes properly during patch (fix #3325)
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jul 26, 2016
1 parent e84a1a4 commit 74f8b98
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 6 deletions.
11 changes: 7 additions & 4 deletions src/core/instance/render.js
Expand Up @@ -103,13 +103,16 @@ export function renderMixin (Vue: Class<Component>) {
// 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
Expand Down
11 changes: 9 additions & 2 deletions src/core/vdom/patch.js
Expand Up @@ -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 &&
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions src/core/vdom/vnode.js
Expand Up @@ -14,6 +14,7 @@ export default class VNode {
child: Component | void;
parent: VNode | void;
raw: ?boolean;
isStatic: ?boolean;

constructor (
tag?: string,
Expand All @@ -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.
Expand Down
20 changes: 20 additions & 0 deletions test/unit/modules/vdom/patch/children.spec.js
Expand Up @@ -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')
})
})

0 comments on commit 74f8b98

Please sign in to comment.