Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 Composition API reference—script setup macros, reactivity, lifecycle hooks, and built-in components
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/advanced-patterns.md
1---2name: advanced-patterns3description: Vue 3 built-in components (Transition, Teleport, Suspense, KeepAlive) and advanced directives4---56# Built-in Components & Directives78## Transition910Animate enter/leave of a single element or component.1112```vue13<template>14<Transition name="fade">15<div v-if="show">Content</div>16</Transition>17</template>1819<style>20.fade-enter-active, .fade-leave-active {21transition: opacity 0.3s ease;22}23.fade-enter-from, .fade-leave-to {24opacity: 0;25}26</style>27```2829### CSS Classes3031| Class | When |32|-------|------|33| `{name}-enter-from` | Start state for enter |34| `{name}-enter-active` | Active state for enter (add transitions here) |35| `{name}-enter-to` | End state for enter |36| `{name}-leave-from` | Start state for leave |37| `{name}-leave-active` | Active state for leave |38| `{name}-leave-to` | End state for leave |3940### Transition Modes4142```vue43<!-- Wait for leave to complete before enter -->44<Transition name="fade" mode="out-in">45<component :is="currentView" />46</Transition>47```4849### JavaScript Hooks5051```vue52<Transition53@before-enter="onBeforeEnter"54@enter="onEnter"55@after-enter="onAfterEnter"56@leave="onLeave"57:css="false"58>59<div v-if="show">Content</div>60</Transition>6162<script setup lang="ts">63function onEnter(el: Element, done: () => void) {64// Animate with JS library65gsap.to(el, { opacity: 1, onComplete: done })66}67</script>68```6970### Appear on Initial Render7172```vue73<Transition appear name="fade">74<div>Shows with animation on mount</div>75</Transition>76```7778## TransitionGroup7980Animate list items. Each child must have a unique `key`.8182```vue83<template>84<TransitionGroup name="list" tag="ul">85<li v-for="item in items" :key="item.id">86{{ item.text }}87</li>88</TransitionGroup>89</template>9091<style>92.list-enter-active, .list-leave-active {93transition: all 0.3s ease;94}95.list-enter-from, .list-leave-to {96opacity: 0;97transform: translateX(30px);98}99/* Move animation for reordering */100.list-move {101transition: transform 0.3s ease;102}103</style>104```105106## Teleport107108Render content to a different DOM location.109110```vue111<template>112<button @click="open = true">Open Modal</button>113114<Teleport to="body">115<div v-if="open" class="modal">116Modal content rendered at body117</div>118</Teleport>119</template>120```121122### Props123124```vue125<!-- CSS selector -->126<Teleport to="#modal-container">127128<!-- DOM element -->129<Teleport :to="targetElement">130131<!-- Disable teleport conditionally -->132<Teleport to="body" :disabled="isMobile">133134<!-- Defer until target exists (Vue 3.5+) -->135<Teleport defer to="#late-rendered-target">136```137138## Suspense139140Handle async dependencies with loading states. **Experimental feature.**141142```vue143<template>144<Suspense>145<template #default>146<AsyncComponent />147</template>148<template #fallback>149<div>Loading...</div>150</template>151</Suspense>152</template>153```154155### Async Dependencies156157Suspense waits for:158- Components with `async setup()`159- Components using top-level `await` in `<script setup>`160- Async components created with `defineAsyncComponent`161162```vue163<!-- AsyncComponent.vue -->164<script setup lang="ts">165const data = await fetch('/api/data').then(r => r.json())166</script>167```168169### Events170171```vue172<Suspense173@pending="onPending"174@resolve="onResolve"175@fallback="onFallback"176>177...178</Suspense>179```180181## KeepAlive182183Cache component instances when toggled.184185```vue186<template>187<KeepAlive>188<component :is="currentTab" />189</KeepAlive>190</template>191```192193### Include/Exclude194195```vue196<!-- By name (string or regex) -->197<KeepAlive include="ComponentA,ComponentB">198<KeepAlive :include="/^Tab/">199<KeepAlive :include="['TabA', 'TabB']">200201<!-- Exclude -->202<KeepAlive exclude="ModalComponent">203204<!-- Max cached instances -->205<KeepAlive :max="10">206```207208### Lifecycle Hooks209210```ts211import { onActivated, onDeactivated } from 'vue'212213onActivated(() => {214// Called when component is inserted from cache215fetchLatestData()216})217218onDeactivated(() => {219// Called when component is removed to cache220pauseTimers()221})222```223224## v-memo225226Skip re-renders when dependencies unchanged. Use for performance optimization.227228```vue229<template>230<div v-for="item in list" :key="item.id" v-memo="[item.selected]">231<!-- Only re-renders when item.selected changes -->232<ExpensiveComponent :item="item" />233</div>234</template>235```236237Equivalent to `v-once` when empty:238```vue239<div v-memo="[]">Never updates</div>240```241242## v-once243244Render once, skip all future updates.245246```vue247<span v-once>Static: {{ neverChanges }}</span>248```249250## Custom Directives251252Create reusable DOM manipulations.253254```ts255// Directive definition256const vFocus: Directive<HTMLElement> = {257mounted: (el) => el.focus()258}259260// Full hooks261const vColor: Directive<HTMLElement, string> = {262created(el, binding, vnode, prevVnode) {},263beforeMount(el, binding) {},264mounted(el, binding) {265el.style.color = binding.value266},267beforeUpdate(el, binding) {},268updated(el, binding) {269el.style.color = binding.value270},271beforeUnmount(el, binding) {},272unmounted(el, binding) {}273}274```275276### Directive Arguments & Modifiers277278```vue279<div v-color:background.bold="'red'">280281<script setup lang="ts">282const vColor: Directive<HTMLElement, string> = {283mounted(el, binding) {284// binding.arg = 'background'285// binding.modifiers = { bold: true }286// binding.value = 'red'287el.style[binding.arg || 'color'] = binding.value288if (binding.modifiers.bold) {289el.style.fontWeight = 'bold'290}291}292}293</script>294```295296### Global Registration297298```ts299// main.ts300app.directive('focus', {301mounted: (el) => el.focus()302})303```304305<!--306Source references:307- https://vuejs.org/api/built-in-components.html308- https://vuejs.org/guide/built-ins/transition.html309- https://vuejs.org/guide/built-ins/teleport.html310- https://vuejs.org/guide/built-ins/suspense.html311- https://vuejs.org/guide/built-ins/keep-alive.html312- https://vuejs.org/api/built-in-directives.html313- https://vuejs.org/guide/reusability/custom-directives.html314-->315