Skip to Content
Nextra 4.0 is released 🎉

Vue 学习指南

Vue 是一个渐进式 JavaScript 框架,用于构建用户界面。它易学易用,性能出色,具有丰富的生态系统。

🚀 快速开始

创建 Vue 项目

# 使用 Vue CLI npm create vue@latest my-vue-app # 使用 Vite (推荐) npm create vite@latest my-vue-app -- --template vue # 使用 Nuxt.js npx nuxi@latest init my-nuxt-app

📚 核心概念

模板语法

Vue 使用基于 HTML 的模板语法,允许声明式地将数据渲染到 DOM:

<template> <div class="container"> <h1>{{ message }}</h1> <p v-if="showText">Welcome to Vue!</p> <button @click="incrementCount">Count: {{ count }}</button> </div> </template> <script setup> import { ref } from 'vue' const message = ref('Hello, Vue!') const count = ref(0) const showText = ref(true) const incrementCount = () => { count.value++ } </script>

组件基础

Vue 组件是 Vue 应用的基本构建块:

<!-- 单文件组件 (SFC) --> <template> <div class="welcome"> <h2>Hello, {{ name }}!</h2> <slot>默认内容</slot> </div> </template> <script setup> defineProps({ name: { type: String, required: true } }) </script> <style scoped> .welcome { padding: 20px; border: 1px solid #ddd; } </style>

⚡ 组合式 API

组合式 API 是 Vue 3 引入的新特性,提供更好的逻辑复用和类型推导。

ref 和 reactive - 响应式数据

<template> <div> <p>Count: {{ count }}</p> <p>User: {{ user.name }} - {{ user.age }}</p> <button @click="increment">Increment</button> </div> </template> <script setup> import { ref, reactive } from 'vue' // ref 用于基本类型 const count = ref(0) // reactive 用于对象 const user = reactive({ name: 'John', age: 25 }) const increment = () => { count.value++ user.age++ } </script>

computed - 计算属性

<template> <div> <input v-model="firstName" placeholder="First name" /> <input v-model="lastName" placeholder="Last name" /> <p>Full name: {{ fullName }}</p> <p>Name length: {{ nameLength }}</p> </div> </template> <script setup> import { ref, computed } from 'vue' const firstName = ref('') const lastName = ref('') // 计算属性 const fullName = computed(() => { return `${firstName.value} ${lastName.value}`.trim() }) const nameLength = computed(() => fullName.value.length) </script>

watch 和 watchEffect - 侦听器

<script setup> import { ref, watch, watchEffect } from 'vue' const count = ref(0) const message = ref('') // 侦听特定数据 watch(count, (newValue, oldValue) => { console.log(`Count changed from ${oldValue} to ${newValue}`) message.value = `Count is now ${newValue}` }) // 自动侦听依赖 watchEffect(() => { console.log(`Count is ${count.value}`) if (count.value > 10) { message.value = 'Count is too high!' } }) </script>

🎯 常用组合式 API

API用途示例
ref响应式引用const count = ref(0)
reactive响应式对象const state = reactive({ count: 0 })
computed计算属性const doubled = computed(() => count.value * 2)
watch侦听器watch(source, callback)
watchEffect自动侦听watchEffect(() => console.log(count.value))
provide/inject依赖注入provide('key', value) / inject('key')

🔧 性能优化

defineAsyncComponent

<script setup> import { defineAsyncComponent } from 'vue' // 异步组件 const AsyncComponent = defineAsyncComponent(() => import('./HeavyComponent.vue') ) </script> <template> <AsyncComponent /> </template>

v-memo

<template> <div v-memo="[user.id, user.name]"> <!-- 只有当 user.id 或 user.name 改变时才重新渲染 --> <h3>{{ user.name }}</h3> <p>{{ user.email }}</p> </div> </template>

组件懒加载

<script setup> import { defineAsyncComponent } from 'vue' const LazyComponent = defineAsyncComponent({ loader: () => import('./LazyComponent.vue'), loadingComponent: LoadingSpinner, errorComponent: ErrorComponent, delay: 200, timeout: 3000 }) </script>

📦 状态管理

Pinia (推荐)

npm install pinia
// stores/counter.js import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, name: 'Counter' }), getters: { doubleCount: (state) => state.count * 2, doubleCountPlusOne() { return this.doubleCount + 1 } }, actions: { increment() { this.count++ }, async fetchCount() { const response = await fetch('/api/count') this.count = await response.json() } } })
<template> <div> <p>Count: {{ counter.count }}</p> <p>Double: {{ counter.doubleCount }}</p> <button @click="counter.increment">Increment</button> </div> </template> <script setup> import { useCounterStore } from '@/stores/counter' const counter = useCounterStore() </script>

Vuex (传统方案)

// store/index.js import { createStore } from 'vuex' export default createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++ } }, actions: { async incrementAsync({ commit }) { await new Promise(resolve => setTimeout(resolve, 1000)) commit('increment') } }, getters: { doubleCount: state => state.count * 2 } })

🛠️ 实用工具和库

路由管理

npm install vue-router@4
// router/index.js import { createRouter, createWebHistory } from 'vue-router' import Home from '@/views/Home.vue' const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: () => import('@/views/About.vue') }, { path: '/user/:id', name: 'User', component: () => import('@/views/User.vue'), props: true } ] const router = createRouter({ history: createWebHistory(), routes }) export default router
<template> <nav> <router-link to="/">Home</router-link> <router-link to="/about">About</router-link> </nav> <router-view /> </template>

样式解决方案

  • CSS Modules: 局部作用域 CSS
  • Tailwind CSS: 实用优先的 CSS 框架
  • UnoCSS: 即时原子化 CSS 引擎
  • Vuetify: Material Design 组件库
  • Element Plus: 企业级 UI 组件库

测试

npm install @vue/test-utils vitest
<script setup> import { ref } from 'vue' const count = ref(0) const increment = () => count.value++ </script> <template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> </div> </template>
// Counter.test.js import { mount } from '@vue/test-utils' import Counter from './Counter.vue' describe('Counter', () => { test('increments count when button is clicked', async () => { const wrapper = mount(Counter) expect(wrapper.text()).toContain('Count: 0') await wrapper.find('button').trigger('click') expect(wrapper.text()).toContain('Count: 1') }) })

📖 学习资源

官方文档

推荐学习路径

  1. 基础: 模板语法、组件、响应式数据
  2. 进阶: 组合式 API、生命周期、自定义指令
  3. 生态: Vue Router、Pinia、测试
  4. 高级: 性能优化、TypeScript 集成、SSR

🔍 调试工具

  • Vue DevTools: 浏览器扩展,用于调试 Vue 应用
  • Pinia DevTools: Pinia 状态调试
  • Vue SFC Playground: 在线 Vue 组件编辑器

🚀 最佳实践

组件设计

<!-- 好的组件设计 --> <template> <div class="user-card"> <img :src="user.avatar" :alt="user.name" /> <h3>{{ user.name }}</h3> <p>{{ user.email }}</p> <slot name="actions" /> </div> </template> <script setup> // 明确的 props 定义 const props = defineProps({ user: { type: Object, required: true, validator: (value) => { return value.name && value.email } } }) // 明确的事件定义 const emit = defineEmits(['edit', 'delete']) </script>

性能优化技巧

  1. 使用 v-once 处理静态内容
  2. 合理使用 v-memo 避免不必要的重新渲染
  3. 组件懒加载减少初始包大小
  4. 使用 computed 缓存计算结果
  5. 避免在模板中使用复杂表达式

最后更新: 2025年

最近更新:12/9/2025, 2:17:56 AM