963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
6.1 KiB
6.1 KiB
name, description
| name | description |
|---|---|
| advanced-patterns | Vue 3 built-in components (Transition, Teleport, Suspense, KeepAlive) and advanced directives |
Built-in Components & Directives
Transition
Animate enter/leave of a single element or component.
<template>
<Transition name="fade">
<div v-if="show">Content</div>
</Transition>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
CSS Classes
| Class | When |
|---|---|
{name}-enter-from |
Start state for enter |
{name}-enter-active |
Active state for enter (add transitions here) |
{name}-enter-to |
End state for enter |
{name}-leave-from |
Start state for leave |
{name}-leave-active |
Active state for leave |
{name}-leave-to |
End state for leave |
Transition Modes
<!-- Wait for leave to complete before enter -->
<Transition name="fade" mode="out-in">
<component :is="currentView" />
</Transition>
JavaScript Hooks
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@leave="onLeave"
:css="false"
>
<div v-if="show">Content</div>
</Transition>
<script setup lang="ts">
function onEnter(el: Element, done: () => void) {
// Animate with JS library
gsap.to(el, { opacity: 1, onComplete: done });
}
</script>
Appear on Initial Render
<Transition appear name="fade">
<div>Shows with animation on mount</div>
</Transition>
TransitionGroup
Animate list items. Each child must have a unique key.
<template>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</TransitionGroup>
</template>
<style>
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* Move animation for reordering */
.list-move {
transition: transform 0.3s ease;
}
</style>
Teleport
Render content to a different DOM location.
<template>
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">Modal content rendered at body</div>
</Teleport>
</template>
Props
<!-- CSS selector -->
<Teleport to="#modal-container">
<!-- DOM element -->
<Teleport :to="targetElement">
<!-- Disable teleport conditionally -->
<Teleport to="body" :disabled="isMobile">
<!-- Defer until target exists (Vue 3.5+) -->
<Teleport defer to="#late-rendered-target">
Suspense
Handle async dependencies with loading states. Experimental feature.
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
Async Dependencies
Suspense waits for:
- Components with
async setup() - Components using top-level
awaitin<script setup> - Async components created with
defineAsyncComponent
<!-- AsyncComponent.vue -->
<script setup lang="ts">
const data = await fetch('/api/data').then((r) => r.json());
</script>
Events
<Suspense @pending="onPending" @resolve="onResolve" @fallback="onFallback">
...
</Suspense>
KeepAlive
Cache component instances when toggled.
<template>
<KeepAlive>
<component :is="currentTab" />
</KeepAlive>
</template>
Include/Exclude
<!-- By name (string or regex) -->
<KeepAlive include="ComponentA,ComponentB">
<KeepAlive :include="/^Tab/">
<KeepAlive :include="['TabA', 'TabB']">
<!-- Exclude -->
<KeepAlive exclude="ModalComponent">
<!-- Max cached instances -->
<KeepAlive :max="10">
Lifecycle Hooks
import { onActivated, onDeactivated } from 'vue';
onActivated(() => {
// Called when component is inserted from cache
fetchLatestData();
});
onDeactivated(() => {
// Called when component is removed to cache
pauseTimers();
});
v-memo
Skip re-renders when dependencies unchanged. Use for performance optimization.
<template>
<div v-for="item in list" :key="item.id" v-memo="[item.selected]">
<!-- Only re-renders when item.selected changes -->
<ExpensiveComponent :item="item" />
</div>
</template>
Equivalent to v-once when empty:
<div v-memo="[]">Never updates</div>
v-once
Render once, skip all future updates.
<span v-once>Static: {{ neverChanges }}</span>
Custom Directives
Create reusable DOM manipulations.
// Directive definition
const vFocus: Directive<HTMLElement> = {
mounted: (el) => el.focus(),
};
// Full hooks
const vColor: Directive<HTMLElement, string> = {
created(el, binding, vnode, prevVnode) {},
beforeMount(el, binding) {},
mounted(el, binding) {
el.style.color = binding.value;
},
beforeUpdate(el, binding) {},
updated(el, binding) {
el.style.color = binding.value;
},
beforeUnmount(el, binding) {},
unmounted(el, binding) {},
};
Directive Arguments & Modifiers
<div v-color:background.bold="'red'">
<script setup lang="ts">
const vColor: Directive<HTMLElement, string> = {
mounted(el, binding) {
// binding.arg = 'background'
// binding.modifiers = { bold: true }
// binding.value = 'red'
el.style[binding.arg || 'color'] = binding.value
if (binding.modifiers.bold) {
el.style.fontWeight = 'bold'
}
}
}
</script>
Global Registration
// main.ts
app.directive('focus', {
mounted: (el) => el.focus(),
});