vue-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVue 3 Best Practices
Vue 3 最佳实践
Quick Reference
快速参考
| Topic | When to Use | Reference |
|---|---|---|
| TypeScript | Props extraction, generic components, useTemplateRef, JSDoc, reactive props destructure | typescript.md |
| Volar | IDE config, strictTemplates, CSS modules, directive comments, Volar 3.0 migration | volar.md |
| Components | defineModel, deep watch, onWatcherCleanup, useId, deferred teleport | components.md |
| Tooling | moduleResolution, HMR SSR, duplicate plugin detection | tooling.md |
| Testing | Pinia store mocking, setup stores, Vue Router typed params | testing.md |
| 主题 | 使用场景 | 参考链接 |
|---|---|---|
| TypeScript | Props提取、泛型组件、useTemplateRef、JSDoc、响应式Props解构 | typescript.md |
| Volar | IDE配置、strictTemplates、CSS modules、指令注释、Volar 3.0迁移 | volar.md |
| 组件 | defineModel、深度监听、onWatcherCleanup、useId、延迟Teleport | components.md |
| 工具链 | moduleResolution、HMR SSR、重复插件检测 | tooling.md |
| 测试 | Pinia store模拟、setup stores、Vue Router类型化参数 | testing.md |
Essential Patterns
核心模式
Extract Component Props
提取组件Props
typescript
import type { ComponentProps } from 'vue-component-type-helpers'
import MyButton from './MyButton.vue'
type Props = ComponentProps<typeof MyButton>typescript
import type { ComponentProps } from 'vue-component-type-helpers'
import MyButton from './MyButton.vue'
type Props = ComponentProps<typeof MyButton>Reactive Props Destructure (Vue 3.5+)
响应式Props解构(Vue 3.5+)
vue
<script setup lang="ts">
// Destructured props are reactive - preferred in Vue 3.5+
const { name, count = 0 } = defineProps<{ name: string; count?: number }>()
</script>vue
<script setup lang="ts">
// 解构后的Props是响应式的——在Vue 3.5+中推荐使用
const { name, count = 0 } = defineProps<{ name: string; count?: number }>()
</script>useTemplateRef (Vue 3.5+)
useTemplateRef(Vue 3.5+)
vue
<script setup lang="ts">
import { useTemplateRef, onMounted } from 'vue'
const inputRef = useTemplateRef('input') // Auto-typed
onMounted(() => inputRef.value?.focus())
</script>
<template><input ref="input" /></template>vue
<script setup lang="ts">
import { useTemplateRef, onMounted } from 'vue'
const inputRef = useTemplateRef('input') // 自动类型推导
onMounted(() => inputRef.value?.focus())
</script>
<template><input ref="input" /></template>onWatcherCleanup (Vue 3.5+)
onWatcherCleanup(Vue 3.5+)
typescript
import { watch, onWatcherCleanup } from 'vue'
watch(query, async (q) => {
const controller = new AbortController()
onWatcherCleanup(() => controller.abort())
await fetch(`/api?q=${q}`, { signal: controller.signal })
})typescript
import { watch, onWatcherCleanup } from 'vue'
watch(query, async (q) => {
const controller = new AbortController()
onWatcherCleanup(() => controller.abort())
await fetch(`/api?q=${q}`, { signal: controller.signal })
})defineModel with Required
带必填项的defineModel
typescript
// Returns Ref<Item> instead of Ref<Item | undefined>
const model = defineModel<Item>({ required: true })typescript
// 返回Ref<Item>而非Ref<Item | undefined>
const model = defineModel<Item>({ required: true })Deep Watch with Numeric Depth
带数值深度的深度监听
typescript
// Vue 3.5+ - watch array mutations without full traversal
watch(items, handler, { deep: 1 })typescript
// Vue 3.5+ - 无需完整遍历即可监听数组变更
watch(items, handler, { deep: 1 })Pinia Store Test Setup
Pinia Store测试搭建
typescript
import { createTestingPinia } from '@pinia/testing'
import { vi } from 'vitest'
mount(Component, {
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })]
}
})typescript
import { createTestingPinia } from '@pinia/testing'
import { vi } from 'vitest'
mount(Component, {
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })]
}
})Common Mistakes
常见错误
- Using - Use
InstanceType<typeof Component>['$props']insteadComponentProps - Missing in createTestingPinia - Required in @pinia/testing 1.0+
createSpy - Using with union types - Use Reactive Props Destructure
withDefaults - in wrong tsconfig - Add to
strictTemplates, not roottsconfig.app.json - ts_ls with Volar 3.0 - Use vtsls instead (Neovim)
- on large structures - Use numeric depth for performance
deep: true - Watching destructured props directly - Wrap in getter:
watch(() => count, ...) - Random IDs in SSR - Use for hydration-safe IDs
useId()
- 使用——应改用
InstanceType<typeof Component>['$props']ComponentProps - createTestingPinia中缺少——@pinia/testing 1.0+版本必填
createSpy - 将与联合类型一起使用——应使用响应式Props解构
withDefaults - 在错误的tsconfig中设置——应添加到
strictTemplates,而非根目录的tsconfigtsconfig.app.json - Volar 3.0搭配ts_ls使用——应改用vtsls(适用于Neovim)
- 对大型结构设置——为提升性能应使用数值深度
deep: true - 直接监听解构后的Props——应包裹在 getter 中:
watch(() => count, ...) - SSR中使用随机ID——应使用确保 hydration 安全的ID
useId()