Create an Application
Every Vue application starts by creating a new application instance with the createApp
function.
The object we are passing into createApp
is in fact a component. Every app requires a “root component” that can contain other components as its children.
An application instance won’t render anything until its .mount()
method is called. It expects a “container” argument, which can either be an actual DOM element or a selector string
You are not limited to a single application instance on the same page. The createApp
API allows multiple Vue applications to co-exist on the same page, each with its own scope for configuration and global assets
const app1 = createApp({
/* ... */
})
app1.mount('#container-1')
const app2 = createApp({
/* ... */
})
app2.mount('#container-2')
If you are using Vue to enhance server-rendered HTML and only need Vue to control specific parts of a large page, avoid mounting a single Vue application instance on the entire page. Instead, create multiple small application instances and mount them on the elements they are responsible for.
Template Syntax
The double mustaches interprets the data as plain text, not HTML. In order to output real HTML, you will need to use the v-html
directive
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
dynamically binding multiple attributes
<script setup>
const objectOfAttrs = {
id: 'container',
class: 'wrapper'
}
</script>
<template>
<div v-bind="objectOfAttrs"></div>
<div :="objectOfAttrs">for short</div>
</template>
Directives
Directives are special attributes with the v-
prefix. Vue provides a number of built-in directives
It is also possible to use a JavaScript expression in a directive argument by wrapping it with square brackets.
Dynamic arguments
<a v-bind:[attributeName]="url"> ... </a>
<!-- shorthand -->
<a :[attributeName]="url"> ... </a>
Dynamic arguments are expected to evaluate to a string, with the exception of null
. The special value null
can be used to explicitly remove the binding. Any other non-string value will trigger a warning.
Modifiers
Modifiers are special postfixes denoted by a dot, which indicate that a directive should be bound in some special way. For example, the .prevent
modifier tells the v-on
directive to call event.preventDefault()
on the triggered event.
Reactivity
We can create a reactive object or array with the reactive()
, and non-object by the ref()
.
When you mutate reactive state, the DOM is updated automatically. However, it should be noted that the DOM updates are not applied synchronously. Instead, Vue buffers them until the “next tick” in the update cycle to ensure that each component needs to update only once no matter how many state changes you have made.
To wait for the DOM update to complete after a state change, you can use the nextTick() global API
import { nextTick } from 'vue'
function increment() {
count.value++
nextTick(() => {
// access updated DOM
})
}
Reactive Proxy
It is important to note that the returned value from reactive()
is a Proxy of the original object, which is not equal to the original object.
Only the proxy is reactive - mutating the original object will not trigger updates.
To ensure consistent access to the proxy, calling reactive()
on the same object always returns the same proxy, and calling reactive()
on an existing proxy also returns that same proxy
Ref
The reactive()
API has two limitations:
- It only works for object types
- we couldn’t pass it around without losing reactivity.
ref()
allows us to create a “reference” to any value and pass it around without losing reactivity.
When refs are accessed as top-level properties in the template, they are automatically “unwrapped” so there is no need to use .value
.
Computed Properties
For complex logic that includes reactive data, it is recommended to use a computed property.
The computed()
function expects to be passed a getter function, and the returned value is a computed ref.
A computed property automatically tracks its reactive dependencies.
Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as author.books
has not changed, multiple access to publishedBooksMessage
will immediately return the previously computed result without having to run the getter function again. In comparison, a method invocation will always run the function whenever a re-render happens.
This also means the following computed property will never update, because Date.now()
is not a reactive dependency.
const now = computed(() => Date.now())
setter
Computed properties are by default getter-only. If you attempt to assign a new value to a computed property, you will receive a runtime warning. In the rare cases where you need a “writable” computed property, you can create one by providing both a getter and a setter:
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// Note: we are using destructuring assignment syntax here.
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
Now when you run fullName.value = 'John Doe'
, the setter will be invoked and firstName
and lastName
will be updated accordingly.
Class and Style Bindings
Vue provides special enhancements when v-bind
is used with class
and style
. In addition to strings, the expressions can also evaluate to objects or arrays.
<div :class="{ active: isActive }"></div>
The above syntax means the presence of the active
class will be determined by the truthiness of the data property isActive
. We can also bind to a computed property that returns an object.
We can bind :class
to an array to apply a list of classes
<div :class="[isActive ? activeClass : '', errorClass]"></div>
<div :class="[{ active: isActive }, errorClass]"></div>
With Components
When you use the class
attribute on a component with a single root element, those classes will be added to the component’s root element, and merged with any existing class already on it.
If your component has multiple root elements, you would need to define which element will receive this class. You can do this using the $attrs
component property
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
Conditional Rendering
v-if
,v-else-if
and v-else
can be used to attain conditional rendering and they also work for <template>
.
The difference is that an element with v-show
will always be rendered and remain in the DOM; v-show
only toggles the display
CSS property of the element.
v-show
doesn’t support the <template>
element, nor does it work with v-else
.
Generally speaking, v-if
has higher toggle costs while v-show
has higher initial render costs. So prefer v-show
if you need to toggle something very often, and prefer v-if
if the condition is unlikely to change at runtime.
It’s not recommended to use v-if
and v-for
on the same element due to implicit precedence. Refer to style guide for details.
When v-if
and v-for
are both used on the same element, v-if
will be evaluated first.
List Rendering
For nested v-for
, scoping also works similar to nested functions. Each v-for
scope has access to parent scopes.
Similar to template v-if
, you can also use a <template>
tag with v-for
to render a block of multiple elements.
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
When they exist on the same node, v-if
has a higher priority than v-for
. That means the v-if
condition will not have access to variables from the scope of the v-for
This can be fixed by moving v-for
to a wrapping <template>
tag (which is also more explicit):
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key
attribute for each item
When using <template v-for>
, the key
should be placed on the <template>
container
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
with Components
You can directly use v-for
on a component, like any normal element (don’t forget to provide a key
).
However, this won’t automatically pass any data to the component, because components have isolated scopes of their own. In order to pass the iterated data into the component, we should also use props.
<my-component
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
></my-component>
Array Change
Vue wraps an observed array’s mutation methods so they will also trigger view updates. The wrapped methods are:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
There are also non-mutating methods, e.g. filter()
, concat()
and slice()
, which do not mutate the original array but always return a new array. When working with non-mutating methods, we should replace the old array with the new one.
Be careful with reverse()
and sort()
in a computed property! These two methods will mutate the original array, which should be avoided in computed getters. Create a copy of the original array before calling these methods.
- return numbers.reverse() //wrong
+ return [...numbers].reverse() //true
Event Handling
We can use the v-on
directive, which we typically shorten to the @
symbol, to listen to DOM events and run some JavaScript when they’re triggered.
The handler value can be one of the following:
- Inline handlers: Inline JavaScript to be executed when the event is triggered (similar to the native
onclick
attribute). - Method handlers: A property name or path that points to a method defined on the component.
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
The template compiler detects method handlers by checking whether the v-on
value string is a valid JavaScript identifier or property access path.
Sometimes we also need to access the original DOM event in an inline handler. You can pass it into a method using the special $event
variable, or use an inline arrow function.
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<!-- using inline arrow function -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
Event Modifiers
Recall that modifiers are directive postfixes denoted by a dot.
.stop
.prevent
.self
.capture
.once
.passive
<!-- the click event's propagation will be stopped -->
<a @click.stop="doThis"></a>
<!-- the submit event will no longer reload the page -->
<form @submit.prevent="onSubmit"></form>
<!-- modifiers can be chained, and the order matters-->
<a @click.stop.prevent="doThat"></a>
<!-- just the modifier -->
<form @submit.prevent></form>
<!-- only trigger handler if event.target is the element itself -->
<!-- i.e. not from a child element -->
<div @click.self="doThat">...</div>
The .capture
, .once
, and .passive
modifiers mirror the options of the native addEventListener
method.
<!-- use capture mode when adding the event listener -->
<!-- i.e. an event targeting an inner element is handled here before being handled by that element -->
<div @click.capture="doThis">...</div>
<!-- the click event will be triggered at most once -->
<a @click.once="doThis"></a>
<!-- the scroll event's default behavior (scrolling) will happen -->
<!-- immediately, instead of waiting for `onScroll` to complete -->
<!-- in case it contains `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
Key Modifiers
You can directly use any valid key names exposed via KeyboardEvent.key
as modifiers by converting them to kebab-case.
key aliases
Vue provides aliases for the most commonly used keys:
.enter
.tab
.delete
(captures both “Delete” and “Backspace” keys).esc
.space
.up
.down
.left
.right
System Modifier Keys
You can use the following modifiers to trigger mouse or keyboard event listeners only when the corresponding modifier key is pressed:
.ctrl
.alt
.shift
.meta
Note that modifier keys are different from regular keys and when used with keyup
events, they have to be pressed when the event is emitted. In other words, keyup.ctrl
will only trigger if you release a key while holding down ctrl
. It won’t trigger if you release the ctrl
key alone.
.exact
Modifier
The .exact
modifier allows control of the exact combination of system modifiers needed to trigger an event.
<!-- this will fire even if Alt or Shift is also pressed -->
<button @click.ctrl="onClick">A</button>
<!-- this will only fire when Ctrl and no other keys are pressed -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- this will only fire when no system modifiers are pressed -->
<button @click.exact="onClick">A</button>
Mouse Button Modifiers
.left
.right
.middle
These modifiers restrict the handler to events triggered by a specific mouse button.
Form Input Bindings
v-model
will ignore the initial value
, checked
or selected
attributes found on any form elements. It will always treat the current bound JavaScript state as the source of truth. You should declare the initial value on the JavaScript side, using reactivity APIs.
Lifecycle Hooks
There are also other hooks which will be called at different stages of the instance’s lifecycle, with the most commonly used being onMounted
, onUpdated
, and onUnmounted
.
Watchs
With Composition API, we can use the watch
function to trigger a callback whenever a piece of reactive state changes.
watch
’s first argument can be different types of reactive “sources”: it can be a ref (including computed refs), a reactive object, a getter function, or an array of multiple sources.
const x = ref(0)
const y = ref(0)
// single ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// array of multiple sources
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
Do note that you can’t watch a property of a reactive object like this:
const obj = reactive({ count: 0 })
// this won't work because we are passing a number to watch()
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
Instead, use a getter:
// instead, use a getter:
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
watchEffect
watchEffect()
allows us to perform a side effect immediately while automatically tracking the effect’s reactive dependencies.
watch
and watchEffect
both allow us to reactively perform side effects. Their main difference is the way they track their reactive dependencies:
watch
only tracks the explicitly watched source. It won’t track anything accessed inside the callback. In addition, the callback only triggers when the source has actually changed.watch
separates dependency tracking from the side effect, giving us more precise control over when the callback should fire.watchEffect
, on the other hand, combines dependency tracking and side effect into one phase. It automatically tracks every reactive property accessed during its synchronous execution. This is more convenient and typically results in terser code, but makes its reactive dependencies less explicit.
By default, user-created watcher callbacks are called before Vue component updates. This means if you attempt to access the DOM inside a watcher callback, the DOM will be in the state before Vue has applied any updates.
If you want to access the DOM in a watcher callback after Vue has updated it, you need to specify the flush: 'post'
option.
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
Post-flush watchEffect()
also has a convenience alias, watchPostEffect()
.
Watchers declared synchronously inside setup()
or <script setup>
are bound to the owner component instance, and will be automatically stopped when the owner component is unmounted. In most cases, you don’t need to worry about stopping the watcher yourself.
The key here is that the watcher must be created synchronously: if the watcher is created in an async callback, it won’t be bound to the owner component and must be stopped manually to avoid memory leaks.
To manually stop a watcher, use the returned handle function. This works for both watch
and watchEffect
.
Note that there should be very few cases where you need to create watchers asynchronously, and synchronous creation should be preferred whenever possible. If you need to wait for some async data, you can make your watch logic conditional instead.
Template Refs
There may still be cases where we need direct access to the underlying DOM elements. To achieve this, we can use the special ref
attribute:
<input ref="input">
ref
is a special attribute, similar to the key
attribute discussed in the v-for
chapter. It allows us to obtain a direct reference to a specific DOM element or child component instance after it’s mounted.
To obtain the reference with Composition API, we need to declare a ref with the same name
Components
Registration
Global Registration
We can make components available globally in the current Vue application using the app.component()
method.
If using SFCs, you will be registering the imported .vue
files.
The app.component()
method can be chained:
app
.component('ComponentA', ComponentA)
.component('ComponentB', ComponentB)
.component('ComponentC', ComponentC)
Globally registered components can be used in the template of any component within this application
drawbacks
- prevents build systems from removing unused components
- makes dependency relationships less explicit in large applications
Local Registration
When using SFC with <script setup>
, imported components are automatically registered locally.
Note that locally registered components are *not* also available in descendent components.
Props
Vue components require explicit props declaration so that Vue knows what external props passed to the component should be treated as fallthrough attributes.
In SFCs using <script setup>
, props can be declared using the defineProps()
macro.
Events
$emit()
A component can emit custom events directly in template expressions (e.g. in a v-on
handler) using the built-in $emit
function.
<button @click="$emit('someEvent')">click me</button>
The parent can then listen to it using v-on
:
<MyComponent @some-event="callback" />
Like components and props, event names provide an automatic case transformation. Like components and props, event names provide an automatic case transformation.
Unlike native DOM events, component emitted events do not bubble. You can only listen to the events emitted by a direct child component.
It’s sometimes useful to emit a specific value with an event.
All extra arguments passed to
$emit()
after the event name will be forwarded to the listener. For example, with$emit('foo', 1, 2, 3)
the listener function will receive three arguments.
defineEmits
Emitted events can be explicitly declared on the component via the defineEmits()
macro.
Fallthrough Attributes
A “fallthrough attribute” is an attribute or v-on
event listener that is passed to a component, but is not explicitly declared in the receiving component’s props or emits. Common examples of this include class
, style
, and id
attributes.
When a component renders a single root element, fallthrough attributes will be automatically added to the root element’s attributes.
Unlike components with a single root node, components with multiple root nodes do not have an automatic attribute fallthrough behavior. If $attrs
are not bound explicitly, a runtime warning will be issued.
useAttrs
If needed, you can access a component’s fallthrough attributes in <script setup>
using the useAttrs()
API:
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>
Provider/inject
Prop Drilling
We can solve props drilling with provide
and inject
. A parent component can serve as a dependency provider for all its descendants. Any component in the descendant tree, regardless of how deep it is, can inject dependencies provided by components up in its parent chain.
Provide
provide(/* key */ 'message', /* value */ 'hello!')
The provide()
function accepts two arguments. The first argument is called the injection key, which can be a string or a Symbol
. The injection key is used by descendent components to lookup the desired value to inject. A single component can call provide()
multiple times with different injection keys to provide different values.
The second argument is the provided value. The value can be of any type, including reactive state such as refs.
Inject
const message = inject('message')
To inject data provided by an ancestor component, use the inject()
function.
If the provided value is a ref, it will be injected as-is and will not be automatically unwrapped. This allows the injector component to retain the reactivity connection to the provider component.
By default, inject
assumes that the injected key is provided somewhere in the parent chain. In the case where the key is not provided, there will be a runtime warning.
If we want to make an injected property work with optional providers, we need to declare a default value, similar to props
const value = inject('message', 'default value')
It is recommended to keep any mutations to reactive state inside of the *provider* whenever possible.
There may be times when we need to update the data from a injector component. In such cases, we recommend providing a function that is responsible for mutating the state.
provide('location', {
location,
updateLocation
})
Finally, you can wrap the provided value with readonly()
if you want to ensure that the data passed through provide
cannot be mutated by the injected component.
provide('read-only-count', readonly(count))
symbol
const myInjectionKey = Symbol()
provide(myInjectionKey, {
/* data to provide */
})
const injected = inject(myInjectionKey)
Async Components
In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it’s needed. To make that possible, Vue has a defineAsyncComponent
function.
const AsyncComp = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
// ...load component from server
resolve(/* loaded component */)
})
})
// ... use `AsyncComp` like a normal component
ES module dynamic import also returns a Promise, so most of the time we will use it in combination with defineAsyncComponent
. Bundlers like Vite and webpack also support the syntax, so we can use it to import Vue SFCs.
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
Loading and Error States
const AsyncComp = defineAsyncComponent({
// the loader function
loader: () => import('./Foo.vue'),
// A component to use while the async component is loading
loadingComponent: LoadingComponent,
// Delay before showing the loading component. Default: 200ms.
delay: 200,
// A component to use if the load fails
errorComponent: ErrorComponent,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout: 3000
})
Reusability
Composables
In the context of Vue applications, a “composable” is a function that leverages Vue Composition API to encapsulate and reuse stateful logic.
export function useMouse() {
// state encapsulated and managed by the composable
const x = ref(0)
const y = ref(0)
// a composable can update its managed state over time.
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
// a composable can also hook into its owner component's
// lifecycle to setup and teardown side effects.
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// expose managed state as return value
return { x, y }
}
extract the logic into an external file, as a composable function.
The cooler part about composables though, is that you can also nest them: one composable function can call one or more other composable functions. This enables us to compose complex logic using small, isolated units, similar to how we compose an entire application using components.
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
function doFetch() {
// reset state before fetching..
data.value = null
error.value = null
// unref() unwraps potential refs
fetch(unref(url))
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
}
if (isRef(url)) {
// setup reactive re-fetch if input URL is a ref
watchEffect(doFetch)
} else {
// otherwise, just fetch once
// and avoid the overhead of a watcher
doFetch()
}
return { data, error }
}
<script setup>
is the only place where you can call composables after usage of await. The compiler automatically restores the active instance context after the async operation for you.
To some extent, you can think of these extracted cas component-scoped services that can talk to one another.
Custom Directives
In addition to the default set of directives shipped in core (like v-model
or v-show
), Vue also allows you to register your own custom directives.
We have introduced two forms of code reuse in Vue: components and composables. Components are the main building blocks, while composables are focused on reusing stateful logic. Custom directives, on the other hand, are mainly intended for reusing logic that involves low-level DOM access on plain elements.
A custom directive is defined as an object containing lifecycle hooks similar to those of a component.
In <script setup>
, any camelCase variable that starts with the v
prefix can be used as a custom directive. In the example above, vFocus
can be used in the template as v-focus
.
const myDirective = {
// called before bound element's attributes
// or event listeners are applied
created(el, binding, vnode, prevVnode) {
// see below for details on arguments
},
// called right before the element is inserted into the DOM.
beforeMount() {},
// called when the bound element's parent component
// and all its children are mounted.
mounted() {},
// called before the parent component is updated
beforeUpdate() {},
// called after the parent component and
// all of its children have updated
updated() {},
// called before the parent component is unmounted
beforeUnmount() {},
// called when the parent component is unmounted
unmounted() {}
}
}
Directive hooks are passed these arguments:
el
: the element the directive is bound to. This can be used to directly manipulate the DOM.binding
: an object containing the following properties.value
: The value passed to the directive. For example inv-my-directive="1 + 1"
, the value would be2
.oldValue
: The previous value, only available inbeforeUpdate
andupdated
. It is available whether or not the value has changed.arg
: The argument passed to the directive, if any. For example inv-my-directive:foo
, the arg would be"foo"
.modifiers
: An object containing modifiers, if any. For example inv-my-directive.foo.bar
, the modifiers object would be{ foo: true, bar: true }
.instance
: The instance of the component where the directive is used.dir
: the directive definition object.
vnode
: the underlying VNode representing the bound element.prevNode
: the VNode representing the bound element from the previous render. Only available in thebeforeUpdate
andupdated
hooks.
It is also common to globally register custom directives at the app level.
app.directive('focus', {
/* ... */
})
Custom directives should only be used when the desired functionality can only be achieved via direct DOM manipulation. Prefer declarative templating using built-in directives such as
v-bind
when possible because they are more efficient and server-rendering friendly.
shorthand
It’s common for a custom directive to have the same behavior for mounted
and updated
, with no need for the other hooks. In such cases we can define the directive as a function:
app.directive('color', (el, binding) => {
// this will be called for both `mounted` and `updated`
el.style.color = binding.value
})
When used on components, custom directives will always apply to a component’s root node, similar to Fallthrough Attributes.
<MyComponent v-demo="test" />
<!-- template of MyComponent -->
<div> <!-- v-demo directive will be applied here -->
<span>My component content</span>
</div>
Note that components can potentially have more than one root node. When applied to a multi-root component, a directive will be ignored and a warning will be thrown. Unlike attributes, directives can’t be passed to a different element with v-bind="$attrs"
. In general, it is not recommended to use custom directives on components.
Plugins
Plugins are self-contained code that usually add app-level functionality to Vue. This is how we install a plugin:
import { createApp } from 'vue'
const app = createApp({})
app.use(myPlugin, {
/* optional options */
})
A plugin is defined as either an object that exposes an install()
method, or simply a function that acts as the install function itself. The install function receives the app instance along with additional options passed to app.use()
, if any:
const myPlugin = {
install(app, options) {
// configure the app
}
}
There is no strictly defined scope for a plugin, but common scenarios where plugins are useful include:
- Register one or more global components or custom directives with
app.component()
andapp.directive()
. - Make a resource injectable throughout the app by calling
app.provide()
. - Add some global instance properties or methods by attaching them to
app.config.globalProperties
. - A library that needs to perform some combination of the above (e.g. vue-router).
Built-in
Transition
Vue offers two built-in components that can help work with transitions and animations in response to changing state:
<Transition>
for applying animations when an element or component is entering and leaving the DOM.<TransitionGroup>
for applying animations when an element or component is inserted into, removed from, or moved within av-for
list.
<Transition>
only supports a single element or component as its slot content. If the content is a component, the component must also have only one single root element.
When an element in a <Transition>
component is inserted or removed, this is what happens:
- Vue will automatically sniff whether the target element has CSS transitions or animations applied. If it does, a number of CSS transition classes will be added / removed at appropriate timings.
- If there are listeners for JavaScript hooks, these hooks will be called at appropriate timings.
- If no CSS transitions / animations are detected and no JavaScript hooks are provided, the DOM operations for insertion and/or removal will be executed on the browser’s next animation frame.
v-enter-from
: Starting state for enter. Added before the element is inserted, removed one frame after the element is inserted.v-enter-active
: Active state for enter. Applied during the entire entering phase. Added before the element is inserted, removed when the transition/animation finishes. This class can be used to define the duration, delay and easing curve for the entering transition.v-enter-to
: Ending state for enter. Added one frame after the element is inserted (at the same timev-enter-from
is removed), removed when the transition/animation finishes.v-leave-from
: Starting state for leave. Added immediately when a leaving transition is triggered, removed after one frame.v-leave-active
: Active state for leave. Applied during the entire leaving phase. Added immediately when a leave transition is triggered, removed when the transition/animation finishes. This class can be used to define the duration, delay and easing curve for the leaving transition.v-leave-to
: Ending state for leave. Added one frame after a leaving transition is triggered (at the same timev-leave-from
is removed), removed when the transition/animation finishes.
For a named transition, its transition classes will be prefixed with its name instead of v
.
<Transition name="fade">
...
</Transition>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
TransitionGroup
<TransitionGroup>
is a built-in component designed for animating the insertion, removal, and order change of elements or components that are rendered in a list.
KeepAlive
<KeepAlive>
is a built-in component that allows us to conditionally cache component instances (to keep the state) when dynamically switching between multiple components.
<!-- Inactive components will be cached! -->
<KeepAlive>
<component :is="activeComponent" />
</KeepAlive>
Teleport
<Teleport>
is a built-in component that allows us to “teleport” a part of a component’s template into a DOM node that exists outside the DOM hierarchy of that component.
Suspense
……