Skip to content

Commit 6f4601c

Browse files
committed
test transition-group
1 parent b8c3b5a commit 6f4601c

File tree

6 files changed

+346
-35
lines changed

6 files changed

+346
-35
lines changed

src/core/vdom/patch.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ export function createPatchFunction (backend) {
218218
}
219219
}
220220

221-
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue) {
221+
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
222222
let oldStartIdx = 0
223223
let newStartIdx = 0
224224
let oldEndIdx = oldCh.length - 1
@@ -229,6 +229,11 @@ export function createPatchFunction (backend) {
229229
let newEndVnode = newCh[newEndIdx]
230230
let oldKeyToIdx, idxInOld, elmToMove, before
231231

232+
// removeOnly is a special flag used only by <transition-group>
233+
// to ensure removed elements stay in correct relative positions
234+
// during leaving transitions
235+
const canMove = !removeOnly
236+
232237
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
233238
if (isUndef(oldStartVnode)) {
234239
oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
@@ -244,12 +249,12 @@ export function createPatchFunction (backend) {
244249
newEndVnode = newCh[--newEndIdx]
245250
} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
246251
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
247-
nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
252+
canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
248253
oldStartVnode = oldCh[++oldStartIdx]
249254
newEndVnode = newCh[--newEndIdx]
250255
} else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
251256
patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
252-
nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
257+
canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
253258
oldEndVnode = oldCh[--oldEndIdx]
254259
newStartVnode = newCh[++newStartIdx]
255260
} else {
@@ -274,7 +279,7 @@ export function createPatchFunction (backend) {
274279
} else {
275280
patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
276281
oldCh[idxInOld] = undefined
277-
nodeOps.insertBefore(parentElm, newStartVnode.elm, oldStartVnode.elm)
282+
canMove && nodeOps.insertBefore(parentElm, newStartVnode.elm, oldStartVnode.elm)
278283
newStartVnode = newCh[++newStartIdx]
279284
}
280285
}
@@ -288,7 +293,7 @@ export function createPatchFunction (backend) {
288293
}
289294
}
290295

291-
function patchVnode (oldVnode, vnode, insertedVnodeQueue) {
296+
function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
292297
if (oldVnode === vnode) return
293298
let i, hook
294299
const hasData = isDef(i = vnode.data)
@@ -304,7 +309,7 @@ export function createPatchFunction (backend) {
304309
}
305310
if (isUndef(vnode.text)) {
306311
if (isDef(oldCh) && isDef(ch)) {
307-
if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue)
312+
if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
308313
} else if (isDef(ch)) {
309314
if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
310315
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
@@ -384,7 +389,7 @@ export function createPatchFunction (backend) {
384389
}
385390
}
386391

387-
return function patch (oldVnode, vnode, hydrating) {
392+
return function patch (oldVnode, vnode, hydrating, removeOnly) {
388393
let elm, parent
389394
let isInitialPatch = false
390395
const insertedVnodeQueue = []
@@ -396,7 +401,7 @@ export function createPatchFunction (backend) {
396401
} else {
397402
const isRealElement = isDef(oldVnode.nodeType)
398403
if (!isRealElement && sameVnode(oldVnode, vnode)) {
399-
patchVnode(oldVnode, vnode, insertedVnodeQueue)
404+
patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly)
400405
} else {
401406
if (isRealElement) {
402407
// mounting to a real element

src/platforms/web/runtime/components/transition-group.js

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ export default {
3030
props,
3131

3232
render (h) {
33-
const prevMap = this.map
34-
const map = this.map = {}
33+
const tag = this.tag || this.$vnode.data.tag || 'span'
34+
const map = Object.create(null)
35+
const prevChildren = this.prevChildren = this.children
3536
const rawChildren = this.$slots.default || []
36-
const children = []
37-
const kept = []
37+
const children = this.children = []
3838
const transitionData = extractTransitionData(this)
3939

4040
for (let i = 0; i < rawChildren.length; i++) {
@@ -44,12 +44,6 @@ export default {
4444
children.push(c)
4545
map[c.key] = c
4646
;(c.data || (c.data = {})).transition = transitionData
47-
const prev = prevMap && prevMap[c.key]
48-
if (prev) {
49-
prev.data.kept = true
50-
c.data.pos = prev.elm.getBoundingClientRect()
51-
kept.push(c)
52-
}
5347
} else if (process.env.NODE_ENV !== 'production') {
5448
const opts = c.componentOptions
5549
const name = opts
@@ -60,30 +54,38 @@ export default {
6054
}
6155
}
6256

63-
const tag = this.tag || this.$vnode.data.tag || 'span'
64-
if (prevMap) {
65-
this.kept = h(tag, null, kept)
66-
this.removed = []
67-
for (const key in prevMap) {
68-
const c = prevMap[key]
69-
if (!c.data.kept) {
70-
c.data.pos = c.elm.getBoundingClientRect()
71-
this.removed.push(c)
57+
if (prevChildren) {
58+
const kept = []
59+
const removed = []
60+
for (let i = 0; i < prevChildren.length; i++) {
61+
const c = prevChildren[i]
62+
c.data.pos = c.elm.getBoundingClientRect()
63+
if (map[c.key]) {
64+
kept.push(c)
65+
} else {
66+
removed.push(c)
7267
}
7368
}
69+
this.kept = h(tag, null, kept)
70+
this.removed = removed
7471
}
7572

7673
return h(tag, null, children)
7774
},
7875

7976
beforeUpdate () {
8077
// force removing pass
81-
this.__patch__(this._vnode, this.kept)
78+
this.__patch__(
79+
this._vnode,
80+
this.kept,
81+
false, // hydrating
82+
true // removeOnly (!important, avoids unnecessary moves)
83+
)
8284
this._vnode = this.kept
8385
},
8486

8587
updated () {
86-
const children = this.kept.children.concat(this.removed)
88+
const children = this.prevChildren
8789
const moveClass = this.moveClass || (this.name + '-move')
8890
if (!children.length || !this.hasMove(children[0].elm, moveClass)) {
8991
return
@@ -108,12 +110,13 @@ export default {
108110
children.forEach(c => {
109111
if (c.data.moved) {
110112
const el = c.elm
113+
/* istanbul ignore if */
114+
if (el._pendingMoveCb) {
115+
el._pendingMoveCb()
116+
}
111117
const s = el.style
112118
addTransitionClass(el, moveClass)
113119
s.transform = s.WebkitTransform = s.transitionDuration = ''
114-
if (el._pendingMoveCb) {
115-
el.removeEventListener(transitionEndEvent, el._pendingMoveCb)
116-
}
117120
el.addEventListener(transitionEndEvent, el._pendingMoveCb = function cb () {
118121
el.removeEventListener(transitionEndEvent, cb)
119122
el._pendingMoveCb = null
@@ -125,6 +128,7 @@ export default {
125128

126129
methods: {
127130
hasMove (el, moveClass) {
131+
/* istanbul ignore if */
128132
if (!hasTransition) {
129133
return false
130134
}

src/platforms/web/runtime/modules/transition.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* @flow */
22

33
import { inBrowser } from 'core/util/index'
4+
import { isIE9 } from 'web/util/index'
45
import { cached, extend } from 'shared/util'
56
import { mergeVNodeHook } from 'core/vdom/helpers'
67
import {
@@ -52,7 +53,7 @@ export function enter (vnode: VNodeWithData) {
5253
const afterEnterHook = isAppear ? (afterAppear || afterEnter) : afterEnter
5354
const enterCancelledHook = isAppear ? (appearCancelled || enterCancelled) : enterCancelled
5455

55-
const expectsCSS = css !== false
56+
const expectsCSS = css !== false && !isIE9
5657
const userWantsControl =
5758
enterHook &&
5859
// enterHook may be a bound method which exposes
@@ -127,7 +128,7 @@ export function leave (vnode: VNodeWithData, rm: Function) {
127128
delayLeave
128129
} = data
129130

130-
const expectsCSS = css !== false
131+
const expectsCSS = css !== false && !isIE9
131132
const userWantsControl =
132133
leave &&
133134
// leave hook may be a bound method which exposes

test/unit/features/transition/inject-styles.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export default function injectStyles () {
1515
-webkit-transition: opacity ${duration}ms ease;
1616
transition: opacity ${duration}ms ease;
1717
}
18+
.group-move {
19+
-webkit-transition: -webkit-transform ${duration}ms ease;
20+
transition: transform ${duration}ms ease;
21+
}
1822
.v-appear, .v-enter, .v-leave-active,
1923
.test-appear, .test-enter, .test-leave-active,
2024
.hello, .bye.active,

0 commit comments

Comments
 (0)