Vue 3 基础教程
欢迎来到 Vue 3 基础教程!本教程将带您从零开始学习 Vue 3 的核心概念和用法。
什么是 Vue 3?
Vue 3 是一个用于构建用户界面的渐进式 JavaScript 框架。相比 Vue 2,Vue 3 带来了:
- 🚀 更好的性能 - 更小的包体积,更快的渲染速度
- 🔧 Composition API - 更灵活的逻辑复用方式
- 📦 更好的 TypeScript 支持 - 原生 TypeScript 支持
- 🌳 Tree-shaking 友好 - 按需引入,减少包体积
环境准备
安装 Node.js
确保您的系统已安装 Node.js 16+ 版本:
bash
node --version
npm --version
创建 Vue 3 项目
使用 Vite 创建新项目(推荐):
bash
npm create vue@latest my-vue-app
cd my-vue-app
npm install
npm run dev
或使用 Vue CLI:
bash
npm install -g @vue/cli
vue create my-vue-app
cd my-vue-app
npm run serve
基础语法
模板语法
Vue 使用基于 HTML 的模板语法:
vue
<template>
<div>
<!-- 文本插值 -->
<h1>{{ message }}</h1>
<!-- 属性绑定 -->
<img :src="imageUrl" :alt="imageAlt">
<!-- 事件监听 -->
<button @click="handleClick">点击我</button>
<!-- 条件渲染 -->
<p v-if="isVisible">这段文字是可见的</p>
<!-- 列表渲染 -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
</div>
</template>
响应式数据
使用 ref
和 reactive
创建响应式数据:
vue
<script setup>
import { ref, reactive } from 'vue'
// 基本类型使用 ref
const count = ref(0)
const message = ref('Hello Vue 3!')
// 对象类型使用 reactive
const user = reactive({
name: '张三',
age: 25,
email: 'zhangsan@example.com'
})
// 修改数据
const increment = () => {
count.value++
}
const updateUser = () => {
user.name = '李四'
user.age = 30
}
</script>
组件基础
单文件组件
Vue 组件通常写在 .vue
文件中:
vue
<!-- UserCard.vue -->
<template>
<div class="user-card">
<img :src="user.avatar" :alt="user.name" class="avatar">
<div class="info">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<button @click="$emit('follow', user.id)">关注</button>
</div>
</div>
</template>
<script setup>
// 定义 props
const props = defineProps({
user: {
type: Object,
required: true
}
})
// 定义 emits
const emit = defineEmits(['follow'])
</script>
<style scoped>
.user-card {
display: flex;
padding: 16px;
border: 1px solid #ddd;
border-radius: 8px;
margin-bottom: 16px;
}
.avatar {
width: 60px;
height: 60px;
border-radius: 50%;
margin-right: 16px;
}
.info h3 {
margin: 0 0 8px 0;
color: #333;
}
.info p {
margin: 0 0 12px 0;
color: #666;
}
</style>
使用组件
vue
<template>
<div>
<h1>用户列表</h1>
<UserCard
v-for="user in users"
:key="user.id"
:user="user"
@follow="handleFollow"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import UserCard from './components/UserCard.vue'
const users = ref([
{
id: 1,
name: '张三',
email: 'zhangsan@example.com',
avatar: '/avatars/zhangsan.svg'
},
{
id: 2,
name: '李四',
email: 'lisi@example.com',
avatar: '/avatars/lisi.svg'
}
])
const handleFollow = (userId) => {
console.log(`关注用户: ${userId}`)
}
</script>
Composition API
基本用法
Composition API 提供了更灵活的逻辑组织方式:
vue
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
// 响应式状态
const count = ref(0)
const name = ref('')
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 侦听器
watch(count, (newValue, oldValue) => {
console.log(`count 从 ${oldValue} 变为 ${newValue}`)
})
// 生命周期钩子
onMounted(() => {
console.log('组件已挂载')
})
// 方法
const increment = () => {
count.value++
}
</script>
组合式函数
创建可复用的逻辑:
javascript
// composables/useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const reset = () => {
count.value = initialValue
}
return {
count,
doubleCount,
increment,
decrement,
reset
}
}
使用组合式函数:
vue
<script setup>
import { useCounter } from '@/composables/useCounter'
const { count, doubleCount, increment, decrement, reset } = useCounter(10)
</script>
<template>
<div>
<p>计数: {{ count }}</p>
<p>双倍: {{ doubleCount }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
<button @click="reset">重置</button>
</div>
</template>
状态管理
使用 Pinia
安装 Pinia:
bash
npm install pinia
创建 store:
javascript
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
currentUser: null,
users: []
}),
getters: {
isLoggedIn: (state) => !!state.currentUser,
userCount: (state) => state.users.length
},
actions: {
async login(credentials) {
try {
const response = await api.login(credentials)
this.currentUser = response.data.user
} catch (error) {
throw error
}
},
logout() {
this.currentUser = null
},
async fetchUsers() {
try {
const response = await api.getUsers()
this.users = response.data
} catch (error) {
console.error('获取用户列表失败:', error)
}
}
}
})
在组件中使用:
vue
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// 访问状态
console.log(userStore.currentUser)
console.log(userStore.isLoggedIn)
// 调用 actions
const handleLogin = async () => {
try {
await userStore.login({ email, password })
router.push('/dashboard')
} catch (error) {
console.error('登录失败:', error)
}
}
</script>
路由管理
使用 Vue Router
安装 Vue Router:
bash
npm install vue-router@4
配置路由:
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import User from '@/views/User.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user/:id',
name: 'User',
component: User,
props: true
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
在组件中使用:
vue
<script setup>
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
// 编程式导航
const goToUser = (userId) => {
router.push(`/user/${userId}`)
}
// 获取路由参数
console.log(route.params.id)
</script>
<template>
<div>
<!-- 声明式导航 -->
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
<!-- 路由出口 -->
<router-view />
</div>
</template>
实战项目
让我们创建一个简单的待办事项应用:
vue
<!-- TodoApp.vue -->
<template>
<div class="todo-app">
<h1>待办事项</h1>
<!-- 添加新任务 -->
<form @submit.prevent="addTodo">
<input
v-model="newTodo"
placeholder="输入新任务..."
required
>
<button type="submit">添加</button>
</form>
<!-- 任务列表 -->
<ul class="todo-list">
<li
v-for="todo in filteredTodos"
:key="todo.id"
:class="{ completed: todo.completed }"
>
<input
type="checkbox"
v-model="todo.completed"
>
<span>{{ todo.text }}</span>
<button @click="removeTodo(todo.id)">删除</button>
</li>
</ul>
<!-- 过滤器 -->
<div class="filters">
<button
v-for="filter in filters"
:key="filter"
:class="{ active: currentFilter === filter }"
@click="currentFilter = filter"
>
{{ filter }}
</button>
</div>
<!-- 统计信息 -->
<p>
总计: {{ todos.length }} |
已完成: {{ completedCount }} |
未完成: {{ remainingCount }}
</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
// 状态
const newTodo = ref('')
const todos = ref([])
const currentFilter = ref('全部')
const filters = ['全部', '未完成', '已完成']
// 计算属性
const completedCount = computed(() =>
todos.value.filter(todo => todo.completed).length
)
const remainingCount = computed(() =>
todos.value.filter(todo => !todo.completed).length
)
const filteredTodos = computed(() => {
switch (currentFilter.value) {
case '未完成':
return todos.value.filter(todo => !todo.completed)
case '已完成':
return todos.value.filter(todo => todo.completed)
default:
return todos.value
}
})
// 方法
const addTodo = () => {
if (newTodo.value.trim()) {
todos.value.push({
id: Date.now(),
text: newTodo.value.trim(),
completed: false
})
newTodo.value = ''
}
}
const removeTodo = (id) => {
const index = todos.value.findIndex(todo => todo.id === id)
if (index > -1) {
todos.value.splice(index, 1)
}
}
</script>
<style scoped>
.todo-app {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.todo-list {
list-style: none;
padding: 0;
}
.todo-list li {
display: flex;
align-items: center;
padding: 10px;
border-bottom: 1px solid #eee;
}
.todo-list li.completed span {
text-decoration: line-through;
color: #999;
}
.filters button {
margin-right: 10px;
padding: 5px 10px;
border: 1px solid #ddd;
background: white;
cursor: pointer;
}
.filters button.active {
background: #007bff;
color: white;
}
</style>
下一步学习
恭喜您完成了 Vue 3 基础教程!接下来可以学习:
参考资源
继续您的 Vue 3 学习之旅吧!🚀