format: apply repo prettier (3.8.1) to the folded skills tree

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.
This commit is contained in:
fargo
2026-08-19 14:37:17 -05:00
parent d2eeb64433
commit 1a822493ba
962 changed files with 29594 additions and 27188 deletions
+34 -24
View File
@@ -3,7 +3,7 @@ name: vue
description: Vue 3 Composition API, script setup macros, reactivity system, and built-in components. Use when writing Vue SFCs, defineProps/defineEmits/defineModel, watchers, or using Transition/Teleport/Suspense/KeepAlive.
metadata:
author: Anthony Fu
version: "2026.1.31"
version: '2026.1.31'
source: Generated from https://github.com/vuejs/docs, scripts at https://github.com/antfu/skills
---
@@ -21,15 +21,15 @@ metadata:
## Core
| Topic | Description | Reference |
|-------|-------------|-----------|
| Script Setup & Macros | `<script setup>`, defineProps, defineEmits, defineModel, defineExpose, defineOptions, defineSlots, generics | [script-setup-macros](references/script-setup-macros.md) |
| Reactivity & Lifecycle | ref, shallowRef, computed, watch, watchEffect, effectScope, lifecycle hooks, composables | [core-new-apis](references/core-new-apis.md) |
| Topic | Description | Reference |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| Script Setup & Macros | `<script setup>`, defineProps, defineEmits, defineModel, defineExpose, defineOptions, defineSlots, generics | [script-setup-macros](references/script-setup-macros.md) |
| Reactivity & Lifecycle | ref, shallowRef, computed, watch, watchEffect, effectScope, lifecycle hooks, composables | [core-new-apis](references/core-new-apis.md) |
## Features
| Topic | Description | Reference |
|-------|-------------|-----------|
| Topic | Description | Reference |
| -------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------- |
| Built-in Components & Directives | Transition, Teleport, Suspense, KeepAlive, v-memo, custom directives | [advanced-patterns](references/advanced-patterns.md) |
## Quick Reference
@@ -38,28 +38,31 @@ metadata:
```vue
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { ref, computed, watch, onMounted } from 'vue';
const props = defineProps<{
title: string
count?: number
}>()
title: string;
count?: number;
}>();
const emit = defineEmits<{
update: [value: string]
}>()
update: [value: string];
}>();
const model = defineModel<string>()
const model = defineModel<string>();
const doubled = computed(() => (props.count ?? 0) * 2)
const doubled = computed(() => (props.count ?? 0) * 2);
watch(() => props.title, (newVal) => {
console.log('Title changed:', newVal)
})
watch(
() => props.title,
(newVal) => {
console.log('Title changed:', newVal);
},
);
onMounted(() => {
console.log('Component mounted')
})
console.log('Component mounted');
});
</script>
<template>
@@ -71,14 +74,21 @@ onMounted(() => {
```ts
// Reactivity
import { ref, shallowRef, computed, reactive, readonly, toRef, toRefs, toValue } from 'vue'
import { ref, shallowRef, computed, reactive, readonly, toRef, toRefs, toValue } from 'vue';
// Watchers
import { watch, watchEffect, watchPostEffect, onWatcherCleanup } from 'vue'
import { watch, watchEffect, watchPostEffect, onWatcherCleanup } from 'vue';
// Lifecycle
import { onMounted, onUpdated, onUnmounted, onBeforeMount, onBeforeUpdate, onBeforeUnmount } from 'vue'
import {
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount,
} from 'vue';
// Utilities
import { nextTick, defineComponent, defineAsyncComponent } from 'vue'
import { nextTick, defineComponent, defineAsyncComponent } from 'vue';
```
@@ -17,10 +17,12 @@ Animate enter/leave of a single element or component.
</template>
<style>
.fade-enter-active, .fade-leave-active {
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
@@ -28,14 +30,14 @@ Animate enter/leave of a single element or component.
### CSS Classes
| Class | When |
|-------|------|
| `{name}-enter-from` | Start state for enter |
| 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 |
| `{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
@@ -62,7 +64,7 @@ Animate enter/leave of a single element or component.
<script setup lang="ts">
function onEnter(el: Element, done: () => void) {
// Animate with JS library
gsap.to(el, { opacity: 1, onComplete: done })
gsap.to(el, { opacity: 1, onComplete: done });
}
</script>
```
@@ -89,10 +91,12 @@ Animate list items. Each child must have a unique `key`.
</template>
<style>
.list-enter-active, .list-leave-active {
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
.list-enter-from, .list-leave-to {
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
@@ -110,11 +114,9 @@ Render content to a different DOM location.
```vue
<template>
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">
Modal content rendered at body
</div>
<div v-if="open" class="modal">Modal content rendered at body</div>
</Teleport>
</template>
```
@@ -155,6 +157,7 @@ Handle async dependencies with loading states. **Experimental feature.**
### Async Dependencies
Suspense waits for:
- Components with `async setup()`
- Components using top-level `await` in `<script setup>`
- Async components created with `defineAsyncComponent`
@@ -162,18 +165,14 @@ Suspense waits for:
```vue
<!-- AsyncComponent.vue -->
<script setup lang="ts">
const data = await fetch('/api/data').then(r => r.json())
const data = await fetch('/api/data').then((r) => r.json());
</script>
```
### Events
```vue
<Suspense
@pending="onPending"
@resolve="onResolve"
@fallback="onFallback"
>
<Suspense @pending="onPending" @resolve="onResolve" @fallback="onFallback">
...
</Suspense>
```
@@ -208,17 +207,17 @@ Cache component instances when toggled.
### Lifecycle Hooks
```ts
import { onActivated, onDeactivated } from 'vue'
import { onActivated, onDeactivated } from 'vue';
onActivated(() => {
// Called when component is inserted from cache
fetchLatestData()
})
fetchLatestData();
});
onDeactivated(() => {
// Called when component is removed to cache
pauseTimers()
})
pauseTimers();
});
```
## v-memo
@@ -235,6 +234,7 @@ Skip re-renders when dependencies unchanged. Use for performance optimization.
```
Equivalent to `v-once` when empty:
```vue
<div v-memo="[]">Never updates</div>
```
@@ -254,23 +254,23 @@ Create reusable DOM manipulations.
```ts
// Directive definition
const vFocus: Directive<HTMLElement> = {
mounted: (el) => el.focus()
}
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
el.style.color = binding.value;
},
beforeUpdate(el, binding) {},
updated(el, binding) {
el.style.color = binding.value
el.style.color = binding.value;
},
beforeUnmount(el, binding) {},
unmounted(el, binding) {}
}
unmounted(el, binding) {},
};
```
### Directive Arguments & Modifiers
@@ -298,8 +298,8 @@ const vColor: Directive<HTMLElement, string> = {
```ts
// main.ts
app.directive('focus', {
mounted: (el) => el.focus()
})
mounted: (el) => el.focus(),
});
```
<!--
@@ -10,16 +10,16 @@ description: Vue 3 reactivity system, lifecycle hooks, and composable patterns
### ref vs shallowRef
```ts
import { ref, shallowRef } from 'vue'
import { ref, shallowRef } from 'vue';
// ref - deep reactivity (tracks nested changes)
const user = ref({ name: 'John', profile: { age: 30 } })
user.value.profile.age = 31 // Triggers reactivity
const user = ref({ name: 'John', profile: { age: 30 } });
user.value.profile.age = 31; // Triggers reactivity
// shallowRef - only .value assignment triggers reactivity (better performance)
const data = shallowRef({ items: [] })
data.value.items.push('new') // Does NOT trigger reactivity
data.value = { items: ['new'] } // Triggers reactivity
const data = shallowRef({ items: [] });
data.value.items.push('new'); // Does NOT trigger reactivity
data.value = { items: ['new'] }; // Triggers reactivity
```
**Prefer `shallowRef`** for large data structures or when deep reactivity is unnecessary.
@@ -27,30 +27,32 @@ data.value = { items: ['new'] } // Triggers reactivity
### computed
```ts
import { ref, computed } from 'vue'
import { ref, computed } from 'vue';
const count = ref(0)
const count = ref(0);
// Read-only computed
const doubled = computed(() => count.value * 2)
const doubled = computed(() => count.value * 2);
// Writable computed
const plusOne = computed({
get: () => count.value + 1,
set: (val) => { count.value = val - 1 }
})
set: (val) => {
count.value = val - 1;
},
});
```
### reactive & readonly
```ts
import { reactive, readonly } from 'vue'
import { reactive, readonly } from 'vue';
const state = reactive({ count: 0, nested: { value: 1 } })
state.count++ // Reactive
const state = reactive({ count: 0, nested: { value: 1 } });
state.count++; // Reactive
const readonlyState = readonly(state)
readonlyState.count++ // Warning, mutation blocked
const readonlyState = readonly(state);
readonlyState.count++; // Warning, mutation blocked
```
Note: `reactive()` loses reactivity on destructuring. Use `ref()` or `toRefs()`.
@@ -60,32 +62,32 @@ Note: `reactive()` loses reactivity on destructuring. Use `ref()` or `toRefs()`.
### watch
```ts
import { ref, watch } from 'vue'
import { ref, watch } from 'vue';
const count = ref(0)
const count = ref(0);
// Watch single ref
watch(count, (newVal, oldVal) => {
console.log(`Changed from ${oldVal} to ${newVal}`)
})
console.log(`Changed from ${oldVal} to ${newVal}`);
});
// Watch getter
watch(
() => props.id,
(id) => fetchData(id),
{ immediate: true }
)
{ immediate: true },
);
// Watch multiple sources
watch([firstName, lastName], ([first, last]) => {
fullName.value = `${first} ${last}`
})
fullName.value = `${first} ${last}`;
});
// Deep watch with depth limit (Vue 3.5+)
watch(state, callback, { deep: 2 })
watch(state, callback, { deep: 2 });
// Once (Vue 3.4+)
watch(source, callback, { once: true })
watch(source, callback, { once: true });
```
### watchEffect
@@ -93,25 +95,25 @@ watch(source, callback, { once: true })
Runs immediately and auto-tracks dependencies.
```ts
import { ref, watchEffect, onWatcherCleanup } from 'vue'
import { ref, watchEffect, onWatcherCleanup } from 'vue';
const id = ref(1)
const id = ref(1);
watchEffect(async () => {
const controller = new AbortController()
const controller = new AbortController();
// Cleanup on re-run or unmount (Vue 3.5+)
onWatcherCleanup(() => controller.abort())
const res = await fetch(`/api/${id.value}`, { signal: controller.signal })
data.value = await res.json()
})
onWatcherCleanup(() => controller.abort());
const res = await fetch(`/api/${id.value}`, { signal: controller.signal });
data.value = await res.json();
});
// Pause/resume (Vue 3.5+)
const { pause, resume, stop } = watchEffect(() => {})
pause()
resume()
stop()
const { pause, resume, stop } = watchEffect(() => {});
pause();
resume();
stop();
```
### Flush Timing
@@ -121,8 +123,8 @@ stop()
// 'post' - after component update (access updated DOM)
// 'sync' - immediate, use with caution
watch(source, callback, { flush: 'post' })
watchPostEffect(() => {}) // Alias for flush: 'post'
watch(source, callback, { flush: 'post' });
watchPostEffect(() => {}); // Alias for flush: 'post'
```
## Lifecycle Hooks
@@ -136,24 +138,24 @@ import {
onBeforeUnmount,
onUnmounted,
onErrorCaptured,
onActivated, // KeepAlive
onDeactivated, // KeepAlive
onServerPrefetch // SSR only
} from 'vue'
onActivated, // KeepAlive
onDeactivated, // KeepAlive
onServerPrefetch, // SSR only
} from 'vue';
onMounted(() => {
console.log('DOM is ready')
})
console.log('DOM is ready');
});
onUnmounted(() => {
// Cleanup timers, listeners, etc.
})
});
// Error boundary
onErrorCaptured((err, instance, info) => {
console.error(err)
return false // Stop propagation
})
console.error(err);
return false; // Stop propagation
});
```
## Effect Scope
@@ -161,24 +163,24 @@ onErrorCaptured((err, instance, info) => {
Group reactive effects for batch disposal.
```ts
import { effectScope, onScopeDispose } from 'vue'
import { effectScope, onScopeDispose } from 'vue';
const scope = effectScope()
const scope = effectScope();
scope.run(() => {
const count = ref(0)
const doubled = computed(() => count.value * 2)
watch(count, () => console.log(count.value))
const count = ref(0);
const doubled = computed(() => count.value * 2);
watch(count, () => console.log(count.value));
// Cleanup when scope stops
onScopeDispose(() => {
console.log('Scope disposed')
})
})
console.log('Scope disposed');
});
});
// Dispose all effects
scope.stop()
scope.stop();
```
## Composables
@@ -193,21 +195,21 @@ Composables are functions that encapsulate stateful logic using Composition API.
```ts
// composables/useMouse.ts
import { ref, onMounted, onUnmounted } from 'vue'
import { ref, onMounted, onUnmounted } from 'vue';
export function useMouse() {
const x = ref(0)
const y = ref(0)
const x = ref(0);
const y = ref(0);
const update = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
x.value = e.pageX;
y.value = e.pageY;
};
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
onMounted(() => window.addEventListener('mousemove', update));
onUnmounted(() => window.removeEventListener('mousemove', update));
return { x, y }
return { x, y };
}
```
@@ -216,31 +218,31 @@ export function useMouse() {
Use `toValue()` (Vue 3.3+) to normalize refs, getters, or plain values.
```ts
import { ref, watchEffect, toValue, type MaybeRefOrGetter } from 'vue'
import { ref, watchEffect, toValue, type MaybeRefOrGetter } from 'vue';
export function useFetch(url: MaybeRefOrGetter<string>) {
const data = ref(null)
const error = ref(null)
const data = ref(null);
const error = ref(null);
watchEffect(async () => {
data.value = null
error.value = null
try {
const res = await fetch(toValue(url))
data.value = await res.json()
} catch (e) {
error.value = e
}
})
data.value = null;
error.value = null;
return { data, error }
try {
const res = await fetch(toValue(url));
data.value = await res.json();
} catch (e) {
error.value = e;
}
});
return { data, error };
}
// Usage - all work:
useFetch('/api/users')
useFetch(urlRef)
useFetch(() => `/api/users/${props.id}`)
useFetch('/api/users');
useFetch(urlRef);
useFetch(() => `/api/users/${props.id}`);
```
### Return Refs (Not Reactive)
@@ -249,10 +251,10 @@ Always return plain object with refs for destructuring compatibility.
```ts
// Good - preserves reactivity when destructured
return { x, y }
return { x, y };
// Bad - loses reactivity when destructured
return reactive({ x, y })
return reactive({ x, y });
```
<!--
@@ -12,11 +12,11 @@ description: Vue 3 script setup syntax and compiler macros for defining props, e
```vue
<script setup lang="ts">
// Top-level bindings are exposed to template
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
import { ref } from 'vue';
import MyComponent from './MyComponent.vue';
const count = ref(0)
const increment = () => count.value++
const count = ref(0);
const increment = () => count.value++;
</script>
<template>
@@ -32,24 +32,27 @@ Declare component props with full TypeScript support.
```ts
// Type-based declaration (recommended)
const props = defineProps<{
title: string
count?: number
items: string[]
}>()
title: string;
count?: number;
items: string[];
}>();
// With defaults (Vue 3.5+)
const { title, count = 0 } = defineProps<{
title: string
count?: number
}>()
title: string;
count?: number;
}>();
// With defaults (Vue 3.4 and below)
const props = withDefaults(defineProps<{
title: string
items?: string[]
}>(), {
items: () => [] // Use factory for arrays/objects
})
const props = withDefaults(
defineProps<{
title: string;
items?: string[];
}>(),
{
items: () => [], // Use factory for arrays/objects
},
);
```
## defineEmits
@@ -59,14 +62,14 @@ Declare emitted events with typed payloads.
```ts
// Named tuple syntax (recommended)
const emit = defineEmits<{
update: [value: string]
change: [id: number, name: string]
close: []
}>()
update: [value: string];
change: [id: number, name: string];
close: [];
}>();
emit('update', 'new value')
emit('change', 1, 'name')
emit('close')
emit('update', 'new value');
emit('change', 1, 'name');
emit('close');
```
## defineModel
@@ -75,26 +78,31 @@ Two-way binding prop consumed via `v-model`. Available in Vue 3.4+.
```ts
// Basic usage - creates "modelValue" prop
const model = defineModel<string>()
model.value = 'hello' // Emits "update:modelValue"
const model = defineModel<string>();
model.value = 'hello'; // Emits "update:modelValue"
// Named model - consumed via v-model:name
const count = defineModel<number>('count', { default: 0 })
const count = defineModel<number>('count', { default: 0 });
// With modifiers
const [value, modifiers] = defineModel<string>()
const [value, modifiers] = defineModel<string>();
if (modifiers.trim) {
// Handle trim modifier
}
// With transformers
const [value, modifiers] = defineModel({
get(val) { return val?.toLowerCase() },
set(val) { return modifiers.trim ? val?.trim() : val }
})
get(val) {
return val?.toLowerCase();
},
set(val) {
return modifiers.trim ? val?.trim() : val;
},
});
```
Parent usage:
```vue
<Child v-model="name" />
<Child v-model:count="total" />
@@ -106,21 +114,24 @@ Parent usage:
Explicitly expose properties to parent via template refs. Components are closed by default.
```ts
import { ref } from 'vue'
import { ref } from 'vue';
const count = ref(0)
const reset = () => { count.value = 0 }
const count = ref(0);
const reset = () => {
count.value = 0;
};
defineExpose({
count,
reset
})
reset,
});
```
Parent access:
```ts
const childRef = ref<{ count: number; reset: () => void }>()
childRef.value?.reset()
const childRef = ref<{ count: number; reset: () => void }>();
childRef.value?.reset();
```
## defineOptions
@@ -130,8 +141,8 @@ Declare component options without a separate `<script>` block. Available in Vue
```ts
defineOptions({
inheritAttrs: false,
name: 'CustomName'
})
name: 'CustomName',
});
```
## defineSlots
@@ -140,9 +151,9 @@ Provide type hints for slot props. Available in Vue 3.3+.
```ts
const slots = defineSlots<{
default(props: { item: string; index: number }): any
header(props: { title: string }): any
}>()
default(props: { item: string; index: number }): any;
header(props: { title: string }): any;
}>();
```
## Generic Components
@@ -152,20 +163,21 @@ Declare generic type parameters using the `generic` attribute.
```vue
<script setup lang="ts" generic="T extends string | number">
defineProps<{
items: T[]
selected: T
}>()
items: T[];
selected: T;
}>();
</script>
```
Multiple generics with constraints:
```vue
<script setup lang="ts" generic="T, U extends Record<string, T>">
import type { Item } from './types'
import type { Item } from './types';
defineProps<{
data: U
key: keyof U
}>()
data: U;
key: keyof U;
}>();
</script>
```
@@ -175,11 +187,11 @@ Use `vNameOfDirective` naming convention.
```ts
const vFocus = {
mounted: (el: HTMLElement) => el.focus()
}
mounted: (el: HTMLElement) => el.focus(),
};
// Or import and rename
import { myDirective as vMyDirective } from './directives'
import { myDirective as vMyDirective } from './directives';
```
```vue
@@ -194,7 +206,7 @@ Use `await` directly in `<script setup>`. The component becomes async and must b
```vue
<script setup lang="ts">
const data = await fetch('/api/data').then(r => r.json())
const data = await fetch('/api/data').then((r) => r.json());
</script>
```