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 {
|
export interface TransitionProps {
|
||||||
mode?: 'in-out' | 'out-in' | 'default'
|
mode?: 'in-out' | 'out-in' | 'default'
|
||||||
appear?: boolean
|
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
|
// enter
|
||||||
onBeforeEnter?: (el: any) => void
|
onBeforeEnter?: (el: any) => void
|
||||||
onEnter?: (el: any, done: () => void) => void
|
onEnter?: (el: any, done: () => void) => void
|
||||||
@ -139,6 +145,7 @@ if (__DEV__) {
|
|||||||
;(TransitionImpl as ComponentOptions).props = {
|
;(TransitionImpl as ComponentOptions).props = {
|
||||||
mode: String,
|
mode: String,
|
||||||
appear: Boolean,
|
appear: Boolean,
|
||||||
|
persisted: Boolean,
|
||||||
// enter
|
// enter
|
||||||
onBeforeEnter: Function,
|
onBeforeEnter: Function,
|
||||||
onEnter: Function,
|
onEnter: Function,
|
||||||
@ -161,6 +168,7 @@ export const Transition = (TransitionImpl as any) as {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TransitionHooks {
|
export interface TransitionHooks {
|
||||||
|
persisted: boolean
|
||||||
beforeEnter(el: object): void
|
beforeEnter(el: object): void
|
||||||
enter(el: object): void
|
enter(el: object): void
|
||||||
leave(el: object, remove: () => void): void
|
leave(el: object, remove: () => void): void
|
||||||
@ -173,6 +181,7 @@ export interface TransitionHooks {
|
|||||||
function resolveTransitionHooks(
|
function resolveTransitionHooks(
|
||||||
{
|
{
|
||||||
appear,
|
appear,
|
||||||
|
persisted = false,
|
||||||
onBeforeEnter,
|
onBeforeEnter,
|
||||||
onEnter,
|
onEnter,
|
||||||
onAfterEnter,
|
onAfterEnter,
|
||||||
@ -188,6 +197,7 @@ function resolveTransitionHooks(
|
|||||||
performDelayedLeave: () => void
|
performDelayedLeave: () => void
|
||||||
): TransitionHooks {
|
): TransitionHooks {
|
||||||
return {
|
return {
|
||||||
|
persisted,
|
||||||
beforeEnter(el) {
|
beforeEnter(el) {
|
||||||
if (!isMounted && !appear) {
|
if (!isMounted && !appear) {
|
||||||
return
|
return
|
||||||
@ -202,7 +212,10 @@ function resolveTransitionHooks(
|
|||||||
if (!isMounted && !appear) {
|
if (!isMounted && !appear) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let called = false
|
||||||
const afterEnter = (pendingCallbacks.enter = (cancelled?) => {
|
const afterEnter = (pendingCallbacks.enter = (cancelled?) => {
|
||||||
|
if (called) return
|
||||||
|
called = true
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
callHook(onEnterCancelled, [el])
|
callHook(onEnterCancelled, [el])
|
||||||
} else {
|
} else {
|
||||||
@ -223,7 +236,10 @@ function resolveTransitionHooks(
|
|||||||
pendingCallbacks.enter(true /* cancelled */)
|
pendingCallbacks.enter(true /* cancelled */)
|
||||||
}
|
}
|
||||||
callHook(onBeforeLeave, [el])
|
callHook(onBeforeLeave, [el])
|
||||||
|
let called = false
|
||||||
const afterLeave = (pendingCallbacks.leave = (cancelled?) => {
|
const afterLeave = (pendingCallbacks.leave = (cancelled?) => {
|
||||||
|
if (called) return
|
||||||
|
called = true
|
||||||
remove()
|
remove()
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
callHook(onLeaveCancelled, [el])
|
callHook(onLeaveCancelled, [el])
|
||||||
|
@ -367,7 +367,7 @@ export function createRenderer<
|
|||||||
invokeDirectiveHook(props.onVnodeBeforeMount, parentComponent, vnode)
|
invokeDirectiveHook(props.onVnodeBeforeMount, parentComponent, vnode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (transition != null) {
|
if (transition != null && !transition.persisted) {
|
||||||
transition.beforeEnter(el)
|
transition.beforeEnter(el)
|
||||||
}
|
}
|
||||||
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
|
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
|
||||||
@ -385,11 +385,14 @@ export function createRenderer<
|
|||||||
}
|
}
|
||||||
hostInsert(el, container, anchor)
|
hostInsert(el, container, anchor)
|
||||||
const vnodeMountedHook = props && props.onVnodeMounted
|
const vnodeMountedHook = props && props.onVnodeMounted
|
||||||
if (vnodeMountedHook != null || transition != null) {
|
if (
|
||||||
|
vnodeMountedHook != null ||
|
||||||
|
(transition != null && !transition.persisted)
|
||||||
|
) {
|
||||||
queuePostRenderEffect(() => {
|
queuePostRenderEffect(() => {
|
||||||
vnodeMountedHook &&
|
vnodeMountedHook &&
|
||||||
invokeDirectiveHook(vnodeMountedHook, parentComponent, vnode)
|
invokeDirectiveHook(vnodeMountedHook, parentComponent, vnode)
|
||||||
transition && transition.enter(el)
|
transition && !transition.persisted && transition.enter(el)
|
||||||
}, parentSuspense)
|
}, parentSuspense)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1468,11 +1471,19 @@ export function createRenderer<
|
|||||||
const remove = () => {
|
const remove = () => {
|
||||||
hostRemove(vnode.el!)
|
hostRemove(vnode.el!)
|
||||||
if (anchor != null) hostRemove(anchor)
|
if (anchor != null) hostRemove(anchor)
|
||||||
if (transition != null && transition.afterLeave) {
|
if (
|
||||||
|
transition != null &&
|
||||||
|
!transition.persisted &&
|
||||||
|
transition.afterLeave
|
||||||
|
) {
|
||||||
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 { leave, delayLeave } = transition
|
||||||
const performLeave = () => leave(el!, remove)
|
const performLeave = () => leave(el!, remove)
|
||||||
if (delayLeave) {
|
if (delayLeave) {
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
FunctionalComponent
|
FunctionalComponent
|
||||||
} from '@vue/runtime-core'
|
} from '@vue/runtime-core'
|
||||||
import { isObject } from '@vue/shared'
|
import { isObject } from '@vue/shared'
|
||||||
|
import { currentRenderingInstance } from 'packages/runtime-core/src/componentRenderUtils'
|
||||||
|
|
||||||
const TRANSITION = 'transition'
|
const TRANSITION = 'transition'
|
||||||
const ANIMATION = 'animation'
|
const ANIMATION = 'animation'
|
||||||
@ -18,12 +19,12 @@ export interface CSSTransitionProps extends TransitionProps {
|
|||||||
enterFromClass?: string
|
enterFromClass?: string
|
||||||
enterActiveClass?: string
|
enterActiveClass?: string
|
||||||
enterToClass?: string
|
enterToClass?: string
|
||||||
|
appearFromClass?: string
|
||||||
|
appearActiveClass?: string
|
||||||
|
appearToClass?: string
|
||||||
leaveFromClass?: string
|
leaveFromClass?: string
|
||||||
leaveActiveClass?: string
|
leaveActiveClass?: string
|
||||||
leaveToClass?: 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 = (
|
export const CSSTransition: FunctionalComponent = (
|
||||||
@ -36,10 +37,13 @@ if (__DEV__) {
|
|||||||
...(BaseTransition as any).props,
|
...(BaseTransition as any).props,
|
||||||
name: String,
|
name: String,
|
||||||
type: String,
|
type: String,
|
||||||
enterClass: String,
|
enterFromClass: String,
|
||||||
enterActiveClass: String,
|
enterActiveClass: String,
|
||||||
enterToClass: String,
|
enterToClass: String,
|
||||||
leaveClass: String,
|
appearFromClass: String,
|
||||||
|
appearActiveClass: String,
|
||||||
|
appearToClass: String,
|
||||||
|
leaveFromClass: String,
|
||||||
leaveActiveClass: String,
|
leaveActiveClass: String,
|
||||||
leaveToClass: String,
|
leaveToClass: String,
|
||||||
duration: Object
|
duration: Object
|
||||||
@ -53,6 +57,9 @@ function resolveCSSTransitionProps({
|
|||||||
enterFromClass = `${name}-enter-from`,
|
enterFromClass = `${name}-enter-from`,
|
||||||
enterActiveClass = `${name}-enter-active`,
|
enterActiveClass = `${name}-enter-active`,
|
||||||
enterToClass = `${name}-enter-to`,
|
enterToClass = `${name}-enter-to`,
|
||||||
|
appearFromClass = enterFromClass,
|
||||||
|
appearActiveClass = enterActiveClass,
|
||||||
|
appearToClass = enterToClass,
|
||||||
leaveFromClass = `${name}-leave-from`,
|
leaveFromClass = `${name}-leave-from`,
|
||||||
leaveActiveClass = `${name}-leave-active`,
|
leaveActiveClass = `${name}-leave-active`,
|
||||||
leaveToClass = `${name}-leave-to`,
|
leaveToClass = `${name}-leave-to`,
|
||||||
@ -61,7 +68,26 @@ function resolveCSSTransitionProps({
|
|||||||
const durations = normalizeDuration(duration)
|
const durations = normalizeDuration(duration)
|
||||||
const enterDuration = durations && durations[0]
|
const enterDuration = durations && durations[0]
|
||||||
const leaveDuration = durations && durations[1]
|
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 {
|
return {
|
||||||
...baseProps,
|
...baseProps,
|
||||||
@ -72,11 +98,7 @@ function resolveCSSTransitionProps({
|
|||||||
},
|
},
|
||||||
onEnter(el, done) {
|
onEnter(el, done) {
|
||||||
nextFrame(() => {
|
nextFrame(() => {
|
||||||
const resolve = () => {
|
const resolve = () => finishEnter(el, done)
|
||||||
removeTransitionClass(el, enterToClass)
|
|
||||||
removeTransitionClass(el, enterActiveClass)
|
|
||||||
done()
|
|
||||||
}
|
|
||||||
onEnter && onEnter(el, resolve)
|
onEnter && onEnter(el, resolve)
|
||||||
removeTransitionClass(el, enterFromClass)
|
removeTransitionClass(el, enterFromClass)
|
||||||
addTransitionClass(el, enterToClass)
|
addTransitionClass(el, enterToClass)
|
||||||
@ -93,11 +115,7 @@ function resolveCSSTransitionProps({
|
|||||||
addTransitionClass(el, leaveActiveClass)
|
addTransitionClass(el, leaveActiveClass)
|
||||||
addTransitionClass(el, leaveFromClass)
|
addTransitionClass(el, leaveFromClass)
|
||||||
nextFrame(() => {
|
nextFrame(() => {
|
||||||
const resolve = () => {
|
const resolve = () => finishLeave(el, done)
|
||||||
removeTransitionClass(el, leaveToClass)
|
|
||||||
removeTransitionClass(el, leaveActiveClass)
|
|
||||||
done()
|
|
||||||
}
|
|
||||||
onLeave && onLeave(el, resolve)
|
onLeave && onLeave(el, resolve)
|
||||||
removeTransitionClass(el, leaveFromClass)
|
removeTransitionClass(el, leaveFromClass)
|
||||||
addTransitionClass(el, leaveToClass)
|
addTransitionClass(el, leaveToClass)
|
||||||
@ -109,7 +127,9 @@ function resolveCSSTransitionProps({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
onEnterCancelled: finishEnter,
|
||||||
|
onLeaveCancelled: finishLeave
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,10 +181,12 @@ function addTransitionClass(el: ElementWithTransition, cls: string) {
|
|||||||
|
|
||||||
function removeTransitionClass(el: ElementWithTransition, cls: string) {
|
function removeTransitionClass(el: ElementWithTransition, cls: string) {
|
||||||
el.classList.remove(cls)
|
el.classList.remove(cls)
|
||||||
el._vtc!.delete(cls)
|
if (el._vtc) {
|
||||||
|
el._vtc.delete(cls)
|
||||||
if (!el._vtc!.size) {
|
if (!el._vtc!.size) {
|
||||||
el._vtc = undefined
|
el._vtc = undefined
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextFrame(cb: () => void) {
|
function nextFrame(cb: () => void) {
|
||||||
|
@ -66,7 +66,7 @@ export {
|
|||||||
export { withModifiers, withKeys } from './directives/vOn'
|
export { withModifiers, withKeys } from './directives/vOn'
|
||||||
|
|
||||||
// DOM-only components
|
// DOM-only components
|
||||||
export { CSSTransition } from './components/CSSTransition'
|
export { CSSTransition, CSSTransitionProps } from './components/CSSTransition'
|
||||||
|
|
||||||
// re-export everything from core
|
// re-export everything from core
|
||||||
// h, Component, reactivity API, nextTick, flags & types
|
// h, Component, reactivity API, nextTick, flags & types
|
||||||
|
Loading…
x
Reference in New Issue
Block a user