Appearance
Vue.js 速查表
Vue.js 开发中最常用的语法和 API 速查表。
模板语法
插值
vue
<template>
<!-- 文本插值 -->
<p>{{ message }}</p>
<!-- HTML 插值 -->
<p v-html="rawHtml"></p>
<!-- 属性绑定 -->
<div :id="dynamicId"></div>
<!-- 事件绑定 -->
<button @click="handleClick">Click me</button>
</template>
指令
vue
<template>
<!-- 条件渲染 -->
<div v-if="show">Visible</div>
<div v-else-if="anotherCondition">Else if</div>
<div v-else>Hidden</div>
<!-- 列表渲染 -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<!-- 表单绑定 -->
<input v-model="inputValue">
<!-- 修饰符 -->
<form @submit.prevent="onSubmit">
<input @keyup.enter="onEnter">
<input @click.stop="onClick">
</form>
</template>
Composition API
基础用法
javascript
import { ref, reactive, computed, watch, onMounted } from 'vue'
export default {
setup() {
// 响应式数据
const count = ref(0)
const state = reactive({ name: 'Vue' })
// 计算属性
const doubled = computed(() => count.value * 2)
// 监听器
watch(count, (newVal, oldVal) => {
console.log(`Count changed: ${oldVal} -> ${newVal}`)
})
// 生命周期
onMounted(() => {
console.log('Component mounted')
})
// 方法
const increment = () => {
count.value++
}
return {
count,
state,
doubled,
increment
}
}
}
使用 script setup
vue
<script setup>
import { ref, computed, watch } from 'vue'
// 响应式数据
const count = ref(0)
const message = ref('Hello Vue')
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 方法
const increment = () => {
count.value++
}
// 监听器
watch(count, (newVal) => {
console.log('Count is now:', newVal)
})
// Props
defineProps({
title: String,
likes: Number
})
// Emit
const emit = defineEmits(['update:title'])
// 使用组合式函数
import { useUser } from '@/composables/useUser'
const { user, loading, error } = useUser()
</script>
Props & Events
Props 定义
javascript
// 类型定义
const props = defineProps({
// 基础类型
propA: String,
propB: [String, Number],
// 带验证的类型
propC: {
type: String,
required: true
},
propD: {
type: Number,
default: 100
},
// 自定义验证
propE: {
validator(value) {
return ['success', 'warning', 'danger'].includes(value)
}
}
})
// 使用默认值的解构
const { title = 'Default Title' } = defineProps(['title'])
事件发射
javascript
// 定义可发射的事件
const emit = defineEmits(['update:modelValue', 'change'])
// 发射事件
const handleChange = (value) => {
emit('update:modelValue', value)
emit('change', { value, timestamp: Date.now() })
}
状态管理
Pinia Store
javascript
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
// 状态
state: () => ({
count: 0,
name: 'Eduardo'
}),
// 计算属性
getters: {
doubleCount: (state) => state.count * 2,
doublePlusOne() {
return this.doubleCount + 1
}
},
// 动作
actions: {
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.floor(Math.random() * 100)
}
}
})
// 在组件中使用
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const store = useCounterStore()
return { store }
}
}
路由
Vue Router
javascript
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/user/:id',
name: 'User',
component: () => import('@/views/User.vue'),
props: true // 将路由参数作为 props 传入组件
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 在组件中使用
import { useRouter, useRoute } from 'vue-router'
export default {
setup() {
const router = useRouter()
const route = useRoute()
// 导航
const goToUser = (id) => {
router.push(`/user/${id}`)
// 或使用命名路由
// router.push({ name: 'User', params: { id } })
}
// 当前路由参数
console.log(route.params.id)
return { goToUser }
}
}
组件通信
Provide / Inject
javascript
// 父组件
import { provide, ref } from 'vue'
export default {
setup() {
const theme = ref('dark')
provide('theme', theme)
provide('updateTheme', (newTheme) => {
theme.value = newTheme
})
}
}
// 子组件
import { inject } from 'vue'
export default {
setup() {
const theme = inject('theme')
const updateTheme = inject('updateTheme')
return { theme, updateTheme }
}
}
常用 Composables
API 数据获取
javascript
// composables/useApi.js
import { ref, onMounted } from 'vue'
export function useApi(url) {
const data = ref(null)
const loading = ref(true)
const error = ref(null)
const fetchData = async () => {
try {
loading.value = true
error.value = null
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
data.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}
onMounted(fetchData)
return {
data,
loading,
error,
refetch: fetchData
}
}
表单验证
javascript
// composables/useForm.js
import { ref, reactive } from 'vue'
export function useForm(initialData = {}, validationRules = {}) {
const formData = reactive({ ...initialData })
const errors = ref({})
const isSubmitting = ref(false)
const validateField = (field, value) => {
const rules = validationRules[field]
if (!rules) return true
for (const rule of rules) {
if (!rule.validator(value)) {
errors.value[field] = rule.message
return false
}
}
delete errors.value[field]
return true
}
const validate = () => {
let isValid = true
for (const field in validationRules) {
if (!validateField(field, formData[field])) {
isValid = false
}
}
return isValid
}
const submit = async (onSubmit) => {
if (!validate()) return
isSubmitting.value = true
try {
await onSubmit(formData)
} catch (err) {
console.error('Form submission error:', err)
} finally {
isSubmitting.value = false
}
}
return {
formData,
errors,
isSubmitting,
validateField,
validate,
submit
}
}
TypeScript 集成
类型定义
typescript
import { ref, computed } from 'vue'
// 接口定义
interface User {
id: number
name: string
email: string
}
interface Props {
user: User
loading?: boolean
disabled?: boolean
}
// 使用 withDefaults 定义默认值
const props = withDefaults(defineProps<Props>(), {
loading: false,
disabled: false
})
// 类型化的事件
interface Emits {
(e: 'update:user', user: User): void
(e: 'delete'): void
}
const emit = defineEmits<Emits>()
// 类型化的响应式数据
const users = ref<User[]>([])
const currentUser = ref<User | null>(null)
const userCount = computed<number>(() => users.value.length)
性能优化
组件懒加载
javascript
import { defineAsyncComponent } from 'vue'
// 懒加载组件
const AsyncComponent = defineAsyncComponent(() =>
import('@/components/HeavyComponent.vue')
)
// 带加载状态的懒加载
const LazyComponent = defineAsyncComponent({
loader: () => import('@/components/HeavyComponent.vue'),
loadingComponent: () => import('@/components/LoadingSpinner.vue'),
errorComponent: () => import('@/components/ErrorComponent.vue'),
delay: 200, // 延迟显示加载组件
timeout: 3000 // 超时时间
})
Memoization
vue
<template>
<!-- 使用 v-memo 优化列表渲染 -->
<div v-for="item in list" :key="item.id">
<div v-memo="[item.id, item.selected]">
<ExpensiveComponent :item="item" />
</div>
</div>
</template>
测试
组件测试
javascript
// tests/components/Button.spec.js
import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'
import Button from '@/components/Button.vue'
describe('Button', () => {
it('renders correctly', () => {
const wrapper = mount(Button, {
props: { text: 'Click me' }
})
expect(wrapper.text()).toContain('Click me')
})
it('emits click event', async () => {
const wrapper = mount(Button)
await wrapper.trigger('click')
expect(wrapper.emitted('click')).toBeTruthy()
})
it('applies correct classes', () => {
const wrapper = mount(Button, {
props: { variant: 'primary', size: 'large' }
})
expect(wrapper.classes()).toContain('btn-primary')
expect(wrapper.classes()).toContain('btn-large')
})
})
构建和部署
Vite 配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router'],
ui: ['element-plus', 'ant-design-vue']
}
}
}
},
server: {
port: 3000,
open: true
}
})
这份速查表涵盖了 Vue.js 开发中的核心概念和常用语法,可以作为日常开发的参考。