Vue 3 全面介绍与实践指南
·
Vue 3 是一个现代化的前端框架,在性能、开发体验和功能方面都有显著提升。下面详细介绍 Vue 3 的核心特性,并提供一个实际的示例。
Vue 3 核心特性
1. Composition API
-
更灵活的逻辑组织和复用
-
更好的 TypeScript 支持
-
更清晰的逻辑关注点分离
2. 性能提升
-
更小的打包体积(Tree-shaking 优化)
-
更快的渲染速度
-
更高效的重渲染机制
3. 更好的 TypeScript 支持
-
完整的 TypeScript 类型定义
-
更好的开发体验
实际示例:任务管理器
下面是一个使用 Vue 3 实现的任务管理器应用:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 3 任务管理器</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
color: #333;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.app-title {
text-align: center;
color: white;
margin-bottom: 30px;
font-size: 2.5rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
padding: 25px;
margin-bottom: 20px;
}
.input-group {
display: flex;
margin-bottom: 20px;
}
.task-input {
flex: 1;
padding: 12px 15px;
border: 2px solid #e1e5e9;
border-radius: 8px 0 0 8px;
font-size: 16px;
transition: border-color 0.3s;
}
.task-input:focus {
outline: none;
border-color: #667eea;
}
.add-btn {
background: #667eea;
color: white;
border: none;
padding: 12px 25px;
border-radius: 0 8px 8px 0;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}
.add-btn:hover {
background: #5a6fd8;
}
.filter-buttons {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.filter-btn {
flex: 1;
padding: 10px;
background: #f1f3f4;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.filter-btn.active {
background: #667eea;
color: white;
}
.task-list {
list-style: none;
}
.task-item {
display: flex;
align-items: center;
padding: 15px;
border-bottom: 1px solid #eaeaea;
transition: background 0.2s;
}
.task-item:hover {
background: #f9f9f9;
}
.task-item:last-child {
border-bottom: none;
}
.task-checkbox {
margin-right: 15px;
transform: scale(1.2);
}
.task-text {
flex: 1;
font-size: 16px;
}
.task-text.completed {
text-decoration: line-through;
color: #888;
}
.delete-btn {
background: #ff6b6b;
color: white;
border: none;
padding: 8px 12px;
border-radius: 6px;
cursor: pointer;
transition: background 0.3s;
}
.delete-btn:hover {
background: #ff5252;
}
.stats {
display: flex;
justify-content: space-between;
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eaeaea;
color: #666;
}
.empty-state {
text-align: center;
padding: 30px;
color: #888;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<h1 class="app-title">Vue 3 任务管理器</h1>
<div class="card">
<div class="input-group">
<input
v-model="newTask"
@keyup.enter="addTask"
class="task-input"
placeholder="添加新任务..."
type="text"
>
<button @click="addTask" class="add-btn">添加任务</button>
</div>
<div class="filter-buttons">
<button
@click="filter = 'all'"
:class="['filter-btn', { active: filter === 'all' }]"
>
全部
</button>
<button
@click="filter = 'active'"
:class="['filter-btn', { active: filter === 'active' }]"
>
待完成
</button>
<button
@click="filter = 'completed'"
:class="['filter-btn', { active: filter === 'completed' }]"
>
已完成
</button>
</div>
<ul class="task-list">
<li v-for="task in filteredTasks" :key="task.id" class="task-item">
<input
type="checkbox"
v-model="task.completed"
class="task-checkbox"
>
<span
:class="['task-text', { completed: task.completed }]"
>
{{ task.text }}
</span>
<button @click="removeTask(task.id)" class="delete-btn">删除</button>
</li>
</ul>
<div v-if="tasks.length === 0" class="empty-state">
还没有任务,添加一个开始吧!
</div>
<div v-if="tasks.length > 0" class="stats">
<span>总计: {{ tasks.length }} 个任务</span>
<span>已完成: {{ completedTasksCount }} 个</span>
<span>待完成: {{ activeTasksCount }} 个</span>
</div>
</div>
</div>
</div>
<script>
const { createApp, ref, computed, onMounted } = Vue;
createApp({
setup() {
// 使用ref创建响应式数据
const newTask = ref('');
const tasks = ref([]);
const filter = ref('all');
// 计算属性
const filteredTasks = computed(() => {
switch (filter.value) {
case 'active':
return tasks.value.filter(task => !task.completed);
case 'completed':
return tasks.value.filter(task => task.completed);
default:
return tasks.value;
}
});
const completedTasksCount = computed(() => {
return tasks.value.filter(task => task.completed).length;
});
const activeTasksCount = computed(() => {
return tasks.value.filter(task => !task.completed).length;
});
// 方法
const addTask = () => {
if (newTask.value.trim() === '') return;
tasks.value.push({
id: Date.now(),
text: newTask.value.trim(),
completed: false
});
newTask.value = '';
saveTasks();
};
const removeTask = (id) => {
tasks.value = tasks.value.filter(task => task.id !== id);
saveTasks();
};
// 本地存储功能
const saveTasks = () => {
localStorage.setItem('vue3-tasks', JSON.stringify(tasks.value));
};
const loadTasks = () => {
const savedTasks = localStorage.getItem('vue3-tasks');
if (savedTasks) {
tasks.value = JSON.parse(savedTasks);
}
};
// 生命周期钩子
onMounted(() => {
loadTasks();
});
// 返回模板中需要使用的数据和方法
return {
newTask,
tasks,
filter,
filteredTasks,
completedTasksCount,
activeTasksCount,
addTask,
removeTask
};
}
}).mount('#app');
</script>
</body>
</html>
Vue 3 核心概念解析
1. 组合式 API (Composition API)
Vue 3 引入了组合式 API,它解决了选项式 API 在复杂组件中逻辑关注点分离的问题。
// 选项式 API (Vue 2)
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
console.log('组件已挂载')
}
}
// 组合式 API (Vue 3)
import { ref, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
count.value++
}
onMounted(() => {
console.log('组件已挂载')
})
return {
count,
increment
}
}
}
2. 响应式系统
Vue 3 使用 Proxy 重写了响应式系统,提供了更好的性能和完善的响应式能力。
import { ref, reactive, computed, watch } from 'vue'
// ref 用于基本类型
const count = ref(0)
// reactive 用于对象
const state = reactive({
user: {
name: '张三',
age: 25
}
})
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 侦听器
watch(count, (newValue, oldValue) => {
console.log(`count 从 ${oldValue} 变为 ${newValue}`)
})
3. 生命周期钩子
Vue 3 的生命周期钩子在组合式 API 中有对应的函数:
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('组件挂载完成')
})
onUpdated(() => {
console.log('组件已更新')
})
onUnmounted(() => {
console.log('组件已卸载')
})
}
}
什么是组件?
组件是 Vue 3 应用的核心构建块,它允许我们将 UI 拆分为独立、可复用的代码片段。每个组件封装了自己的结构、样式和行为,可以像 HTML 元素一样在模板中使用。
组件的基本结构
单文件组件 (SFC)
Vue 组件通常以 .vue 文件形式存在,包含三个部分:
<template>
<!-- HTML 模板 -->
<div class="counter">
<button @click="decrement">-</button>
<span>{{ count }}</span>
<button @click="increment">+</button>
</div>
</template>
<script>
// JavaScript 逻辑
export default {
name: 'Counter',
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
},
decrement() {
this.count--
}
}
}
</script>
<style>
/* CSS 样式 */
.counter {
display: flex;
gap: 10px;
align-items: center;
}
</style>
组件的注册
全局注册
import { createApp } from 'vue'
import MyComponent from './MyComponent.vue'
const app = createApp({})
app.component('my-component', MyComponent)
局部注册
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
export default {
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
}
组件通信
1. Props (父传子)
<!-- 子组件 -->
<template>
<div>
<h3>{{ title }}</h3>
<p>{{ content }}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
},
content: {
type: String,
default: '默认内容'
}
}
}
</script>
<!-- 父组件使用 -->
<child-component title="文章标题" content="文章内容" />
2. 自定义事件 (子传父)
vue
<!-- 子组件 -->
<template>
<button @click="notifyParent">通知父组件</button>
</template>
<script>
export default {
methods: {
notifyParent() {
this.$emit('child-event', '来自子组件的消息')
}
}
}
</script>
<!-- 父组件 -->
<template>
<child-component @child-event="handleChildEvent" />
</template>
<script>
export default {
methods: {
handleChildEvent(message) {
console.log(message) // "来自子组件的消息"
}
}
}
</script>
3. 使用组合式 API 的组件通信
vue
<script setup>
// 定义 props
const props = defineProps({
title: String,
count: Number
})
// 定义事件
const emit = defineEmits(['update:count'])
// 触发事件
const updateCount = (newCount) => {
emit('update:count', newCount)
}
</script>
组件生命周期
Vue 3 组件有完整的生命周期钩子:
<script>
export default {
setup() {
// 组合式 API 生命周期
onBeforeMount(() => {})
onMounted(() => {})
onBeforeUpdate(() => {})
onUpdated(() => {})
onBeforeUnmount(() => {})
onUnmounted(() => {})
},
// 选项式 API 生命周期
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {},
unmounted() {}
}
</script>
插槽 (Slots)
默认插槽
vue
<!-- 子组件 -->
<template>
<div class="card">
<slot>默认内容</slot>
</div>
</template>
<!-- 父组件使用 -->
<card-component>
<p>这是插入的内容</p>
</card-component>
具名插槽
vue
<!-- 子组件 -->
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- 父组件使用 -->
<layout-component>
<template v-slot:header>
<h1>页面标题</h1>
</template>
<p>主要内容</p>
<template #footer> <!-- # 是 v-slot 的简写 -->
<p>页脚内容</p>
</template>
</layout-component>
作用域插槽
vue
<!-- 子组件 -->
<template>
<ul>
<li v-for="item in items" :key="item.id">
<slot :item="item"></slot>
</li>
</ul>
</template>
<!-- 父组件使用 -->
<list-component :items="userList">
<template v-slot:default="slotProps">
<span>{{ slotProps.item.name }} - {{ slotProps.item.age }}</span>
</template>
</list-component>
依赖注入
用于跨层级组件通信:
<!-- 祖先组件 -->
<script>
import { provide } from 'vue'
export default {
setup() {
const theme = 'dark'
provide('theme', theme)
}
}
</script>
<!-- 后代组件 -->
<script>
import { inject } from 'vue'
export default {
setup() {
const theme = inject('theme', 'light') // 第二个参数是默认值
return { theme }
}
}
</script>
动态组件
<template>
<component :is="currentComponent" />
</template>
<script>
import Home from './Home.vue'
import About from './About.vue'
import Contact from './Contact.vue'
export default {
data() {
return {
currentComponent: 'Home'
}
},
components: {
Home,
About,
Contact
}
}
</script>
异步组件
javascript
// 定义异步组件
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
// 带加载状态和错误处理的异步组件
const AsyncComponentWithOptions = defineAsyncComponent({
loader: () => import('./AsyncComponent.vue'),
loadingComponent: LoadingComponent,
errorComponent: ErrorComponent,
delay: 200,
timeout: 3000
})
更多推荐



所有评论(0)