feat(transition): handle persisted mode
This commit is contained in:
parent
cbc2044752
commit
1b8236615e
@ -17,6 +17,12 @@ import { ShapeFlags } from '../shapeFlags'
|
||||
export interface TransitionProps {
|
||||
mode?: 'in-out' | 'out-in' | 'default'
|
||||
appear?: boolean
|
||||
// If true, indicates this is a transition that doesn't actually insert/remove
|
||||
// the element, but toggles the show / hidden status instead.
|
||||
// The transition hooks are injected, but will be skipped by the renderer.
|
||||
// Instead, a custom directive can control the transition by calling the
|
||||
// injected hooks (e.g. v-show).
|
||||
persisted?: boolean
|
||||
// enter
|
||||
onBeforeEnter?: (el: any) => void
|
||||
onEnter?: (el: any, done: () => void) => void
|
||||
@ -139,6 +145,7 @@ if (__DEV__) {
|
||||
;(TransitionImpl as ComponentOptions).props = {
|
||||
mode: String,
|
||||
appear: Boolean,
|
||||
persisted: Boolean,
|
||||
// enter
|
||||
onBeforeEnter: Function,
|
||||
onEnter: Function,
|
||||
@ -161,6 +168,7 @@ export const Transition = (TransitionImpl as any) as {
|
||||
}
|
||||
|
||||
export interface TransitionHooks {
|
||||
persisted: boolean
|
||||
beforeEnter(el: object): void
|
||||
enter(el: object): void
|
||||
leave(el: object, remove: () => void): void
|
||||
@ -173,6 +181,7 @@ export interface TransitionHooks {
|
||||
function resolveTransitionHooks(
|
||||
{
|
||||
appear,
|
||||
persisted = false,
|
||||
onBeforeEnter,
|
||||
onEnter,
|
||||
onAfterEnter,
|
||||
@ -188,6 +197,7 @@ function resolveTransitionHooks(
|
||||
performDelayedLeave: () => void
|
||||
): TransitionHooks {
|
||||
return {
|
||||
persisted,
|
||||
beforeEnter(el) {
|
||||
if (!isMounted && !appear) {
|
||||
return
|
||||
@ -202,7 +212,10 @@ function resolveTransitionHooks(
|
||||
if (!isMounted && !appear) {
|
||||
return
|
||||
}
|
||||
let called = false
|
||||
const afterEnter = (pendingCallbacks.enter = (cancelled?) => {
|
||||
if (called) return
|
||||
called = true
|
||||
if (cancelled) {
|
||||
callHook(onEnterCancelled, [el])
|
||||
} else {
|
||||
@ -223,7 +236,10 @@ function resolveTransitionHooks(
|
||||
pendingCallbacks.enter(true /* cancelled */)
|
||||
}
|
||||
callHook(onBeforeLeave, [el])
|
||||
let called = false
|
||||
const afterLeave = (pendingCallbacks.leave = (cancelled?) => {
|
||||
if (called) return
|
||||
called = true
|
||||
remove()
|
||||
if (cancelled) {
|
||||
callHook(onLeaveCancelled, [el])
|
||||
|
@ -367,7 +367,7 @@ export function createRenderer<
|
||||
invokeDirectiveHook(props.onVnodeBeforeMount, parentComponent, vnode)
|
||||
}
|
||||
}
|
||||
if (transition != null) {
|
||||
if (transition != null && !transition.persisted) {
|
||||
transition.beforeEnter(el)
|
||||
}
|
||||
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
|
||||
@ -385,11 +385,14 @@ export function createRenderer<
|
||||
}
|
||||
hostInsert(el, container, anchor)
|
||||
const vnodeMountedHook = props && props.onVnodeMounted
|
||||
if (vnodeMountedHook != null || transition != null) {
|
||||
if (
|
||||
vnodeMountedHook != null ||
|
||||
(transition != null && !transition.persisted)
|
||||
) {
|
||||
queuePostRenderEffect(() => {
|
||||
vnodeMountedHook &&
|
||||
invokeDirectiveHook(vnodeMountedHook, parentComponent, vnode)
|
||||
transition && transition.enter(el)
|
||||
transition && !transition.persisted && transition.enter(el)
|
||||
}, parentSuspense)
|
||||
}
|
||||
}
|
||||
@ -1468,11 +1471,19 @@ export function createRenderer<
|
||||
const remove = () => {
|
||||
hostRemove(vnode.el!)
|
||||
if (anchor != null) hostRemove(anchor)
|
||||
if (transition != null && transition.afterLeave) {
|
||||
if (
|
||||
transition != null &&
|
||||
!transition.persisted &&
|
||||
transition.afterLeave
|
||||
) {
|
||||
transition.afterLeave()
|
||||
}
|
||||
}
|
||||
if (vnode.shapeFlag & ShapeFlags.ELEMENT && transition != null) {
|
||||
if (
|
||||
vnode.shapeFlag & ShapeFlags.ELEMENT &&
|
||||
transition != null &&
|
||||
!transition.persisted
|
||||
) {
|
||||
const { leave, delayLeave } = transition
|
||||
const performLeave = () => leave(el!, remove)
|
||||
if (delayLeave) {
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
FunctionalComponent
|
||||
} from '@vue/runtime-core'
|
||||
import { isObject } from '@vue/shared'
|
||||
import { currentRenderingInstance } from 'packages/runtime-core/src/componentRenderUtils'
|
||||
|
||||
const TRANSITION = 'transition'
|
||||
const ANIMATION = 'animation'
|
||||
@ -18,12 +19,12 @@ export interface CSSTransitionProps extends TransitionProps {
|
||||
enterFromClass?: string
|
||||
enterActiveClass?: string
|
||||
enterToClass?: string
|
||||
appearFromClass?: string
|
||||
appearActiveClass?: string
|
||||
appearToClass?: string
|
||||
leaveFromClass?: string
|
||||
leaveActiveClass?: string
|
||||
leaveToClass?: string
|
||||
// if present, indicates this is a v-show transition by toggling the
|
||||
// CSS display property instead of actually removing the element.
|
||||
show?: boolean
|
||||
}
|
||||
|
||||
export const CSSTransition: FunctionalComponent = (
|
||||
@ -36,10 +37,13 @@ if (__DEV__) {
|
||||
...(BaseTransition as any).props,
|
||||
name: String,
|
||||
type: String,
|
||||
enterClass: String,
|
||||
enterFromClass: String,
|
||||
enterActiveClass: String,
|
||||
enterToClass: String,
|
||||
leaveClass: String,
|
||||
appearFromClass: String,
|
||||
appearActiveClass: String,
|
||||
appearToClass: String,
|
||||
leaveFromClass: String,
|
||||
leaveActiveClass: String,
|
||||
leaveToClass: String,
|
||||
duration: Object
|
||||
@ -53,6 +57,9 @@ function resolveCSSTransitionProps({
|
||||
enterFromClass = `${name}-enter-from`,
|
||||
enterActiveClass = `${name}-enter-active`,
|
||||
enterToClass = `${name}-enter-to`,
|
||||
appearFromClass = enterFromClass,
|
||||
appearActiveClass = enterActiveClass,
|
||||
appearToClass = enterToClass,
|
||||
leaveFromClass = `${name}-leave-from`,
|
||||
leaveActiveClass = `${name}-leave-active`,
|
||||
leaveToClass = `${name}-leave-to`,
|
||||
@ -61,7 +68,26 @@ function resolveCSSTransitionProps({
|
||||
const durations = normalizeDuration(duration)
|
||||
const enterDuration = durations && durations[0]
|
||||
const leaveDuration = durations && durations[1]
|
||||
const { onBeforeEnter, onEnter, onLeave } = baseProps
|
||||
const { appear, onBeforeEnter, onEnter, onLeave } = baseProps
|
||||
|
||||
// is appearing
|
||||
if (appear && !currentRenderingInstance!.subTree) {
|
||||
enterFromClass = appearFromClass
|
||||
enterActiveClass = appearActiveClass
|
||||
enterToClass = appearToClass
|
||||
}
|
||||
|
||||
function finishEnter(el: Element, done?: () => void) {
|
||||
removeTransitionClass(el, enterToClass)
|
||||
removeTransitionClass(el, enterActiveClass)
|
||||
done && done()
|
||||
}
|
||||
|
||||
function finishLeave(el: Element, done?: () => void) {
|
||||
removeTransitionClass(el, leaveToClass)
|
||||
removeTransitionClass(el, leaveActiveClass)
|
||||
done && done()
|
||||
}
|
||||
|
||||
return {
|
||||
...baseProps,
|
||||
@ -72,11 +98,7 @@ function resolveCSSTransitionProps({
|
||||
},
|
||||
onEnter(el, done) {
|
||||
nextFrame(() => {
|
||||
const resolve = () => {
|
||||
removeTransitionClass(el, enterToClass)
|
||||
removeTransitionClass(el, enterActiveClass)
|
||||
done()
|
||||
}
|
||||
const resolve = () => finishEnter(el, done)
|
||||
onEnter && onEnter(el, resolve)
|
||||
removeTransitionClass(el, enterFromClass)
|
||||
addTransitionClass(el, enterToClass)
|
||||
@ -93,11 +115,7 @@ function resolveCSSTransitionProps({
|
||||
addTransitionClass(el, leaveActiveClass)
|
||||
addTransitionClass(el, leaveFromClass)
|
||||
nextFrame(() => {
|
||||
const resolve = () => {
|
||||
removeTransitionClass(el, leaveToClass)
|
||||
removeTransitionClass(el, leaveActiveClass)
|
||||
done()
|
||||
}
|
||||
const resolve = () => finishLeave(el, done)
|
||||
onLeave && onLeave(el, resolve)
|
||||
removeTransitionClass(el, leaveFromClass)
|
||||
addTransitionClass(el, leaveToClass)
|
||||
@ -109,7 +127,9 @@ function resolveCSSTransitionProps({
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
onEnterCancelled: finishEnter,
|
||||
onLeaveCancelled: finishLeave
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,9 +181,11 @@ function addTransitionClass(el: ElementWithTransition, cls: string) {
|
||||
|
||||
function removeTransitionClass(el: ElementWithTransition, cls: string) {
|
||||
el.classList.remove(cls)
|
||||
el._vtc!.delete(cls)
|
||||
if (!el._vtc!.size) {
|
||||
el._vtc = undefined
|
||||
if (el._vtc) {
|
||||
el._vtc.delete(cls)
|
||||
if (!el._vtc!.size) {
|
||||
el._vtc = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ export {
|
||||
export { withModifiers, withKeys } from './directives/vOn'
|
||||
|
||||
// DOM-only components
|
||||
export { CSSTransition } from './components/CSSTransition'
|
||||
export { CSSTransition, CSSTransitionProps } from './components/CSSTransition'
|
||||
|
||||
// re-export everything from core
|
||||
// h, Component, reactivity API, nextTick, flags & types
|
||||
|
Loading…
x
Reference in New Issue
Block a user