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')
})
})📖 学习资源
官方文档
推荐学习路径
- 基础: 模板语法、组件、响应式数据
- 进阶: 组合式 API、生命周期、自定义指令
- 生态: Vue Router、Pinia、测试
- 高级: 性能优化、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>性能优化技巧
- 使用 v-once 处理静态内容
- 合理使用 v-memo 避免不必要的重新渲染
- 组件懒加载减少初始包大小
- 使用 computed 缓存计算结果
- 避免在模板中使用复杂表达式
最后更新: 2025年
最近更新:12/9/2025, 2:17:56 AM