Skip to content

Commit 998ea85

Browse files
committed
support explicit transition type
1 parent ba5ec54 commit 998ea85

File tree

6 files changed

+110
-31
lines changed

6 files changed

+110
-31
lines changed

src/core/vdom/create-component.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,21 @@ export function createComponent (
9090
)
9191
}
9292

93-
// merge component management hooks onto the placeholder node
94-
mergeHooks(data)
95-
9693
// extract listeners, since these needs to be treated as
9794
// child component listeners instead of DOM listeners
9895
const listeners = data.on
9996
// replace with listeners with .native modifier
10097
data.on = data.nativeOn
10198

99+
if (Ctor.options.abstract) {
100+
// abstract components do not keep anything
101+
// other than props & listeners
102+
data = {}
103+
}
104+
105+
// merge component management hooks onto the placeholder node
106+
mergeHooks(data)
107+
102108
// return a placeholder vnode
103109
const name = Ctor.options.name || tag
104110
const vnode = new VNode(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const transitionProps = {
1212
appear: Boolean,
1313
css: Boolean,
1414
mode: String,
15+
type: String,
1516
enterClass: String,
1617
leaveClass: String,
1718
enterActiveClass: String,

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function enter (vnode: VNodeWithData) {
3232

3333
const {
3434
css,
35+
type,
3536
enterClass,
3637
enterActiveClass,
3738
appearClass,
@@ -99,7 +100,7 @@ export function enter (vnode: VNodeWithData) {
99100
nextFrame(() => {
100101
removeTransitionClass(el, startClass)
101102
if (!cb.cancelled && !userWantsControl) {
102-
whenTransitionEnds(el, cb)
103+
whenTransitionEnds(el, type, cb)
103104
}
104105
})
105106
}
@@ -130,6 +131,7 @@ export function leave (vnode: VNodeWithData, rm: Function) {
130131

131132
const {
132133
css,
134+
type,
133135
leaveClass,
134136
leaveActiveClass,
135137
beforeLeave,
@@ -187,7 +189,7 @@ export function leave (vnode: VNodeWithData, rm: Function) {
187189
nextFrame(() => {
188190
removeTransitionClass(el, leaveClass)
189191
if (!cb.cancelled && !userWantsControl) {
190-
whenTransitionEnds(el, cb)
192+
whenTransitionEnds(el, type, cb)
191193
}
192194
})
193195
}

src/platforms/web/runtime/transition-util.js

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ export function removeTransitionClass (el: any, cls: string) {
4545
removeClass(el, cls)
4646
}
4747

48-
export function whenTransitionEnds (el: Element, cb: Function) {
49-
const { type, timeout, propCount } = getTransitionInfo(el)
48+
export function whenTransitionEnds (
49+
el: Element,
50+
expectedType: ?stirng,
51+
cb: Function
52+
) {
53+
const { type, timeout, propCount } = getTransitionInfo(el, expectedType)
5054
if (!type) return cb()
5155
const event = type === TRANSITION ? transitionEndEvent : animationEndEvent
5256
let ended = 0
@@ -69,34 +73,56 @@ export function whenTransitionEnds (el: Element, cb: Function) {
6973

7074
const transformRE = /\b(transform|all)(,|$)/
7175

72-
export function getTransitionInfo (el: Element): {
73-
type: ?string,
74-
propCount: number,
75-
timeout: number
76+
export function getTransitionInfo (el: Element, expectedType?: ?string): {
77+
type: ?string;
78+
propCount: number;
79+
timeout: number;
7680
} {
7781
const styles = window.getComputedStyle(el)
78-
const transitionProps = styles[transitionProp + 'Property']
7982
const transitioneDelays = styles[transitionProp + 'Delay'].split(', ')
8083
const transitionDurations = styles[transitionProp + 'Duration'].split(', ')
84+
const transitionTimeout = getTimeout(transitioneDelays, transitionDurations)
8185
const animationDelays = styles[animationProp + 'Delay'].split(', ')
8286
const animationDurations = styles[animationProp + 'Duration'].split(', ')
83-
const transitionTimeout = getTimeout(transitioneDelays, transitionDurations)
8487
const animationTimeout = getTimeout(animationDelays, animationDurations)
85-
const timeout = Math.max(transitionTimeout, animationTimeout)
86-
const type = timeout > 0
87-
? transitionTimeout > animationTimeout
88-
? TRANSITION
89-
: ANIMATION
90-
: null
91-
return {
92-
type,
93-
timeout,
94-
propCount: type
88+
89+
let type
90+
let timeout = 0
91+
let propCount = 0
92+
/* istanbul ignore if */
93+
if (expectedType === TRANSITION) {
94+
if (transitionTimeout > 0) {
95+
type = TRANSITION
96+
timeout = transitionTimeout
97+
propCount = transitionDurations.length
98+
}
99+
} else if (expectedType === ANIMATION) {
100+
if (animationTimeout > 0) {
101+
type = ANIMATION
102+
timeout = animationTimeout
103+
propCount = animationDurations.length
104+
}
105+
} else {
106+
timeout = Math.max(transitionTimeout, animationTimeout)
107+
type = timeout > 0
108+
? transitionTimeout > animationTimeout
109+
? TRANSITION
110+
: ANIMATION
111+
: null
112+
propCount = type
95113
? type === TRANSITION
96114
? transitionDurations.length
97115
: animationDurations.length
98-
: 0,
99-
hasTransform: type === TRANSITION && transformRE.test(transitionProps)
116+
: 0
117+
}
118+
const hasTransform =
119+
type === TRANSITION &&
120+
transformRE.test(styles[transitionProp + 'Property'])
121+
return {
122+
type,
123+
timeout,
124+
propCount,
125+
hasTransform
100126
}
101127
}
102128

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ export default function injectStyles () {
3333
animation: test-leave ${duration}ms;
3434
-webkit-animation: test-leave ${duration}ms;
3535
}
36+
.test-anim-long-enter-active {
37+
animation: test-enter ${duration * 2}ms;
38+
-webkit-animation: test-enter ${duration * 2}ms;
39+
}
40+
.test-anim-long-leave-active {
41+
animation: test-leave ${duration * 2}ms;
42+
-webkit-animation: test-leave ${duration * 2}ms;
43+
}
3644
@keyframes test-enter {
3745
from { opacity: 0 }
3846
to { opacity: 1 }

test/unit/features/transition/transition.spec.js

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,28 +488,64 @@ if (!isIE9) {
488488
template: `
489489
<div>
490490
<transition name="test-anim">
491-
<div v-if="ok" class="test">foo</div>
491+
<div v-if="ok">foo</div>
492492
</transition>
493493
</div>
494494
`,
495495
data: { ok: true }
496496
}).$mount(el)
497497

498498
// should not apply transition on initial render by default
499-
expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
499+
expect(vm.$el.innerHTML).toBe('<div>foo</div>')
500500
vm.ok = false
501501
waitForUpdate(() => {
502-
expect(vm.$el.children[0].className).toBe('test test-anim-leave test-anim-leave-active')
502+
expect(vm.$el.children[0].className).toBe('test-anim-leave test-anim-leave-active')
503503
}).thenWaitFor(nextFrame).then(() => {
504-
expect(vm.$el.children[0].className).toBe('test test-anim-leave-active')
504+
expect(vm.$el.children[0].className).toBe('test-anim-leave-active')
505505
}).thenWaitFor(duration + 10).then(() => {
506506
expect(vm.$el.children.length).toBe(0)
507507
vm.ok = true
508508
}).then(() => {
509-
expect(vm.$el.children[0].className).toBe('test test-anim-enter test-anim-enter-active')
509+
expect(vm.$el.children[0].className).toBe('test-anim-enter test-anim-enter-active')
510510
}).thenWaitFor(nextFrame).then(() => {
511-
expect(vm.$el.children[0].className).toBe('test test-anim-enter-active')
511+
expect(vm.$el.children[0].className).toBe('test-anim-enter-active')
512512
}).thenWaitFor(duration + 10).then(() => {
513+
expect(vm.$el.children[0].className).toBe('')
514+
}).then(done)
515+
})
516+
517+
it('explicit transition type', done => {
518+
const vm = new Vue({
519+
template: `
520+
<div>
521+
<transition name="test-anim-long" type="animation">
522+
<div v-if="ok" class="test">foo</div>
523+
</transition>
524+
</div>
525+
`,
526+
data: { ok: true }
527+
}).$mount(el)
528+
529+
// should not apply transition on initial render by default
530+
expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
531+
vm.ok = false
532+
waitForUpdate(() => {
533+
expect(vm.$el.children[0].className).toBe('test test-anim-long-leave test-anim-long-leave-active')
534+
}).thenWaitFor(nextFrame).then(() => {
535+
expect(vm.$el.children[0].className).toBe('test test-anim-long-leave-active')
536+
}).thenWaitFor(duration + 5).then(() => {
537+
// should not end early due to transition presence
538+
expect(vm.$el.children[0].className).toBe('test test-anim-long-leave-active')
539+
}).thenWaitFor(duration + 5).then(() => {
540+
expect(vm.$el.children.length).toBe(0)
541+
vm.ok = true
542+
}).then(() => {
543+
expect(vm.$el.children[0].className).toBe('test test-anim-long-enter test-anim-long-enter-active')
544+
}).thenWaitFor(nextFrame).then(() => {
545+
expect(vm.$el.children[0].className).toBe('test test-anim-long-enter-active')
546+
}).thenWaitFor(duration + 5).then(() => {
547+
expect(vm.$el.children[0].className).toBe('test test-anim-long-enter-active')
548+
}).thenWaitFor(duration + 5).then(() => {
513549
expect(vm.$el.children[0].className).toBe('test')
514550
}).then(done)
515551
})

0 commit comments

Comments
 (0)