Skip to content

Commit 230c6ae

Browse files
committed
fix(vdom): avoid diff de-opt when both head/tail are different
fix #6502
1 parent f76d16e commit 230c6ae

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

src/core/vdom/patch.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,9 @@ export function createPatchFunction (backend) {
401401
newStartVnode = newCh[++newStartIdx]
402402
} else {
403403
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
404-
idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : null
404+
idxInOld = isDef(newStartVnode.key)
405+
? oldKeyToIdx[newStartVnode.key]
406+
: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
405407
if (isUndef(idxInOld)) { // New element
406408
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
407409
newStartVnode = newCh[++newStartIdx]
@@ -435,6 +437,13 @@ export function createPatchFunction (backend) {
435437
}
436438
}
437439

440+
function findIdxInOld (node, oldCh, start, end) {
441+
for (let i = start; i < end; i++) {
442+
const c = oldCh[i]
443+
if (isDef(c) && sameVnode(node, c)) return i
444+
}
445+
}
446+
438447
function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
439448
if (oldVnode === vnode) {
440449
return

test/unit/modules/vdom/patch/children.spec.js

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { patch } from 'web/runtime/patch'
2-
import VNode from 'core/vdom/vnode'
2+
import VNode, { createEmptyVNode } from 'core/vdom/vnode'
33

44
function prop (name) {
55
return obj => { return obj[name] }
@@ -445,7 +445,7 @@ describe('vdom patch: children', () => {
445445
expect(child2.className).toBe('')
446446
})
447447

448-
it('should handle static vnodes properly', function () {
448+
it('should handle static vnodes properly', () => {
449449
function makeNode (text) {
450450
return new VNode('div', undefined, [
451451
new VNode(undefined, undefined, undefined, text)
@@ -466,7 +466,7 @@ describe('vdom patch: children', () => {
466466
expect(elm.textContent).toBe('ABC')
467467
})
468468

469-
it('should handle static vnodes inside ', function () {
469+
it('should handle static vnodes inside ', () => {
470470
function makeNode (text) {
471471
return new VNode('div', undefined, [
472472
new VNode(undefined, undefined, undefined, text)
@@ -486,4 +486,25 @@ describe('vdom patch: children', () => {
486486
elm = patch(vnode2, vnode3)
487487
expect(elm.textContent).toBe('ABC')
488488
})
489+
490+
// #6502
491+
it('should not de-opt when both head and tail are changed', () => {
492+
const vnode1 = new VNode('div', {}, [
493+
createEmptyVNode(),
494+
new VNode('div'),
495+
createEmptyVNode()
496+
])
497+
const vnode2 = new VNode('div', {}, [
498+
new VNode('p'),
499+
new VNode('div'),
500+
new VNode('p')
501+
])
502+
let root = patch(null, vnode1)
503+
const original = root.childNodes[1]
504+
505+
root = patch(vnode1, vnode2)
506+
const postPatch = root.childNodes[1]
507+
508+
expect(postPatch).toBe(original)
509+
})
489510
})

0 commit comments

Comments
 (0)