Vue3 animation and source code analysis
1. How does Vue implement animation
In Vue, animation is mainly displayed through the built-in component < transition > < / transition > provided by Vue.
2. Use
1. Wrap a single element or component
<template> <div> <button @click="isShow = !isShow">toggle</button> <transition name="ydkd"> <h1 v-if="isShow">Content</h1> </transition> </div> </template> <script setup> import { ref } from '@vue/reactivity'; const isShow = ref(true) </script> <style scoped> .ydkd-enter-from, .ydkd-leave-to { opacity: 0; } .ydkd-enter-to, .ydkd-leave-from { opacity: 1; } .ydkd-enter-active, .ydkd-leave-active { transition: all 2s ease; } </style>
2. Wrap multiple elements or components
<template> <div class="container"> <div> <button @click="isShow = !isShow">toggle</button> </div> <transition name="ydkd" mode="out-in" :appear="true"> <h1 class="tip" v-if="isShow">Hello transition</h1> <h1 class="tip" v-else>Hello YDKD</h1> </transition> </div> </template> <script setup> import { ref } from '@vue/reactivity'; const isShow = ref(true); </script> <style scoped> .container { margin: 0 auto; text-align: center; } .tip { display: inline-block; } .ydkd-enter-active { animation: bounce 2s ease; } .ydkd-leave-active { animation: bounce 2s ease reverse; } @keyframes bounce { 0% { transform: scale(0); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } </style>
Details:
- When multiple components are switched, two components will be displayed at the same time. You can set the mode attribute for < transition mode = "out in" > < / transition >, with two values.
- out-in first disappears the current, and then introduces the subsequent
- in-out first enters the subsequent, and then disappears the current
- At the beginning of the page, the user may see the animation, and can give < transition: appearance = "true" > < / transition >, that is, the animation is turned on by default, and the attribute value of appearance is false by default
- In fact, the appear ance attribute is the value of the [name] - enter active attribute of the element. Can be in Source code analysis See in.
3. class of transition animation
V-enter-from - > v-enter-to from hidden to displayed
V-leave-to < - v-leave-from show to hide
V-enter-active < - > v-leave-active transition animation effect from element display to hide / from hide to display
graphic
4. Implementation principle
When Vue finds elements wrapped by < transition > < / transition > during template compilation, Vue will perform the following processing
- 1. Automatically sniff whether CSS transition or animation is applied to the target element. If so, add / delete CSS class names at the appropriate time
- 2. If the transition component provides JavaScript hook functions, these hook functions will be called at the right time;
- 3. If no JavaScript hook is found and no CSS transition / animation is detected, DOM insertion and deletion will be performed immediately
5. Source code analysis
1. The persistent attribute is true and marked as < transition > < / transition >, which means that the insert/remove element will not be performed at present and will be skipped at the render layer.
2. For < transition name = "ydkd" > < / transition >, if name is not set, v will be taken in the source code.
const { name = 'v', type, duration, 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` } = rawProps
3. The < transition > < / transition > component contains many hook functions. When judging the display and hiding of elements, such as the first point of the implementation principle, add / delete CSS class names at the right time. The following functions will be used in the source code.
// Add class name export function addTransitionClass(el: Element, cls: string) { cls.split(/\s+/).forEach(c => c && el.classList.add(c)) ;( (el as ElementWithTransition)._vtc || ((el as ElementWithTransition)._vtc = new Set()) ).add(cls) } // Remove class name export function removeTransitionClass(el: Element, cls: string) { cls.split(/\s+/).forEach(c => c && el.classList.remove(c)) const { _vtc } = el as ElementWithTransition if (_vtc) { _vtc.delete(cls) if (!_vtc!.size) { ;(el as ElementWithTransition)._vtc = undefined } } }