feat(transition): handle transition classes when patching classes

This commit is contained in:
Evan You 2019-11-22 15:31:55 -05:00
parent 7859e4bce3
commit be9b4b2527
2 changed files with 45 additions and 14 deletions

View File

@ -64,19 +64,19 @@ function resolveCSSTransitionData({
...baseProps,
onBeforeEnter(el) {
onBeforeEnter && onBeforeEnter(el)
el.classList.add(enterActiveClass)
el.classList.add(enterFromClass)
addTransitionClass(el, enterActiveClass)
addTransitionClass(el, enterFromClass)
},
onEnter(el, done) {
nextFrame(() => {
const resolve = () => {
el.classList.remove(enterToClass)
el.classList.remove(enterActiveClass)
removeTransitionClass(el, enterToClass)
removeTransitionClass(el, enterActiveClass)
done()
}
onEnter && onEnter(el, resolve)
el.classList.remove(enterFromClass)
el.classList.add(enterToClass)
removeTransitionClass(el, enterFromClass)
addTransitionClass(el, enterToClass)
if (!(onEnter && onEnter.length > 1)) {
if (enterDuration) {
setTimeout(resolve, enterDuration)
@ -87,17 +87,17 @@ function resolveCSSTransitionData({
})
},
onLeave(el, done) {
el.classList.add(leaveActiveClass)
el.classList.add(leaveFromClass)
addTransitionClass(el, leaveActiveClass)
addTransitionClass(el, leaveFromClass)
nextFrame(() => {
const resolve = () => {
el.classList.remove(leaveToClass)
el.classList.remove(leaveActiveClass)
removeTransitionClass(el, leaveToClass)
removeTransitionClass(el, leaveActiveClass)
done()
}
onLeave && onLeave(el, resolve)
el.classList.remove(leaveFromClass)
el.classList.add(leaveToClass)
removeTransitionClass(el, leaveFromClass)
addTransitionClass(el, leaveToClass)
if (!(onLeave && onLeave.length > 1)) {
if (leaveDuration) {
setTimeout(resolve, leaveDuration)
@ -143,6 +143,27 @@ function validateDuration(val: unknown) {
}
}
export interface ElementWithTransition extends Element {
// _vtc = Vue Transition Classes.
// Store the temporarily-added transition classes on the element
// so that we can avoid overwriting them if the element's class is patched
// during the transition.
_vtc?: Set<string>
}
function addTransitionClass(el: ElementWithTransition, cls: string) {
el.classList.add(cls)
;(el._vtc || (el._vtc = new Set())).add(cls)
}
function removeTransitionClass(el: ElementWithTransition, cls: string) {
el.classList.remove(cls)
el._vtc!.delete(cls)
if (!el._vtc!.size) {
el._vtc = undefined
}
}
function nextFrame(cb: () => void) {
requestAnimationFrame(() => {
requestAnimationFrame(cb)

View File

@ -1,7 +1,17 @@
import { ElementWithTransition } from '../components/CSSTransition'
// compiler should normalize class + :class bindings on the same element
// into a single binding ['staticClass', dynamic]
export function patchClass(el: Element, value: string, isSVG: boolean) {
export function patchClass(
el: ElementWithTransition,
value: string,
isSVG: boolean
) {
// if this is an element during a transition, take the temporary transition
// classes into account.
if (el._vtc) {
value = [value, ...el._vtc].join(' ')
}
// directly setting className should be faster than setAttribute in theory
if (isSVG) {
el.setAttribute('class', value)