Skip to content
On this page

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 开发中的核心概念和常用语法,可以作为日常开发的参考。