The Transition component works by adding and removing animation classes. The Transition component works by adding and removing animation classes.
Vue provides a wrapper component for Transition. You can add an entry/exit transition to any element or component in the following cases:
- Conditional Rendering (using V-if)
- Conditional presentation (using V-show)
- Dynamic components
- Component root node
How does Transition sniff if CSS transitions or animations are applied
In conditional rendering, when Vue is mountElement in patch function, the following method is used to sniff transition.
// parentSuspense is related to Suspense components and is not considered for the time being
const monuntElement = function (vnode, / /...). {
const { transition } = vnode
// ...
// Determine whether to use transition
constneedCallTransitionHooks = (! parentSuspense || (parentSuspense && ! parentSuspense.pendingBranch)) && transition && ! transition.persisted// Initialize the animation with the beforEnter hook function
if(needCallTransitionHooks) { transition! .beforeEnter(el) }// ...
}
Copy the code
Transition is resolved from the internal hook function by resolveTransitionHooks and added to the transition property of vNode by setTransitionHooks
// BaseTransition.ts
const BaseTransitionImpl = {
setup (props, { slots }) {
return (() = > {
// ...
// The transition hook is attached to the vnode as vNode. transition
const enterHooks = resolveTransitionHooks(
innerChild,
rawProps,
state,
instance
)
setTransitionHooks(child, enterHooks)
// ...}}})function setTransitionHooks (vnode, hooks) {
if (vnode.shapeFlag & ShapeFlags.COMPONENT && vnode.component) {
setTransitionHooks(vnode.component.subTree, hooks)
} else if(__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) { vnode.ssContent! .transition = hooks.clone(vnode.ssContent!) vnode.ssFallback! .transition = hooks.clone(vnode.ssFallback!) }else {
vnode.transition = hooks / / set the hooks}}Copy the code
ResolveTransitionHooks () => The TransitionHooks method provides methods such as Enter and leave to handle hook functions
interface TransitionHooks {
mode: BaseTransitionProps['mode']
persisted: boolean
beforeEnter(el: HostElement): void
enter(el: HostElement): void
leave(el: HostElement, remove: () = > void) :void
clone(vnode: VNode): TransitionHooks<HostElement>
// optionalafterLeave? () :voiddelayLeave? ( el: HostElement,earlyRemove: () = > void.delayedLeave: () = > void) :voiddelayedLeave? () :void
}
Copy the code
How is the Transition class name added at the right time
When TransitionHooks are called, they trigger the functions generated by the resolveTransitionProps method to add the transition class name when appropriate, similar to our v-enter-active, v-from-active… , and finally ends the transition animation with the whenTransitionEnds method
export const Transition = (props, { slots }) = >
h(BaseTransition, resolveTransitionProps(props), slots)
Copy the code
@runtime-dom/src/components/Transition
// You can check it by yourself
function resolveTransitionProps() {
// ...
// How to add animation Class with Enter example
const makeEnterHook = (isAppear) = > {
return (el, done) = > {
const hook = isAppear ? onAppear : onEnter;
const resolve = () = > finishEnter(el, isAppear, done);
hook && hook(el, resolve); // Calls the hook function passed in when used
nextFrame(() = > {
removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass);
addTransitionClass(el, isAppear ? appearToClass : enterToClass);
if(! (hook && hook.length >1)) { whenTransitionEnds(el, type, enterDuration, resolve); }}); };return {
// ...
onEnter: makeEnterHook(false)}}; }Copy the code
Add/remove the transitionClass method
function addTransitionClass(el, cls) {
cls.split(/\s+/).forEach(c= > c && el.classList.add(c));
(el._vtc ||
(el._vtc = new Set())).add(cls);
}
function removeTransitionClass(el, cls) {
cls.split(/\s+/).forEach(c= > c && el.classList.remove(c));
const { _vtc } = el;
if (_vtc) {
_vtc.delete(cls);
if(! _vtc.size) { el._vtc =undefined; }}}Copy the code
The vShow conditional display triggers the Transition hook function in the vShow instruction
export const vShow = {
beforeMount(el, { value }, { transition }) {
el._vod = el.style.display === 'none' ? ' ' : el.style.display
if (transition && value) {
transition.beforeEnter(el) // before
} else {
setDisplay(el, value)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el) // enter}},updated(el, { value, oldValue }, { transition }) {
// update
if(transition && value ! == oldValue) {if (value) {
transition.beforeEnter(el)
setDisplay(el, true)
transition.enter(el)
} else {
transition.leave(el, () = > {
setDisplay(el, false)}}}else {
setDisplay(el, value)
}
},
beforeUnmount(el, { value }) {
setDisplay(el, value)
}
}
Copy the code
Unload hook functions and TransitionClass
When the component reaches the unmount method, the remove method is called to uninstall the transition animation of the component. VShow is performed in the update command.
const remove = vnode= > {
const { type, el, anchor, transition } = vnode;
// ...
const performRemove = () = > {
hostRemove(el);
if (transition && !transition.persisted && transition.afterLeave) {
transition.afterLeave();
}
};
if (vnode.shapeFlag & 1 /* ELEMENT */&& transition && ! transition.persisted) {const { leave, delayLeave } = transition; / / add leave - the transition - class
const performLeave = () = > leave(el, performRemove);
if (delayLeave) {
delayLeave(vnode.el, performRemove, performLeave);
}
else{ performLeave(); }}else{ performRemove(); }};Copy the code
conclusion
Transition itself does not render a DOM element and does not appear in the parent component chain. Instead, it renders a child node. The Transition code is very clever, and the childVnode Transition property handles the entry/exit of the animation. It is really interesting to learn and think about.
The Transition component is very rich. Personal understanding is limited, I hope to help you. If there are any mistakes, please correct them.