Vue3 学习指南
目录
基础概念
组合式 API
javascript
// 使用 setup
import { ref, computed, onMounted } from 'vue';
export default {
setup() {
// 响应式状态
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
// 方法
function increment() {
count.value++;
}
// 生命周期钩子
onMounted(() => {
console.log('组件已挂载');
});
// 返回模板需要的数据和方法
return {
count,
doubleCount,
increment
};
}
};
// 使用 <script setup>
<script setup>
import { ref, computed, onMounted } from 'vue';
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
onMounted(() => {
console.log('组件已挂载');
});
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>说明:
- setup 函数
- 响应式 API
- 生命周期钩子
- 组合式函数
响应式系统
javascript
import { ref, reactive, computed, watch, watchEffect } from 'vue';
// ref
const count = ref(0);
console.log(count.value); // 0
count.value++;
// reactive
const state = reactive({
count: 0,
double: computed(() => state.count * 2)
});
// watch
watch(count, (newValue, oldValue) => {
console.log('count changed:', oldValue, '->', newValue);
});
// watchEffect
watchEffect(() => {
console.log('count is:', count.value);
});
// 响应式对象
const obj = reactive({
nested: {
count: 0
}
});
// 响应式数组
const arr = reactive([1, 2, 3]);
arr.push(4);
// 响应式 Map
const map = reactive(new Map());
map.set('key', 'value');
// 响应式 Set
const set = reactive(new Set());
set.add(1);说明:
- ref 和 reactive
- computed 属性
- watch 和 watchEffect
- 响应式对象和集合
生命周期
javascript
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue';
export default {
setup() {
onBeforeMount(() => {
console.log('组件挂载前');
});
onMounted(() => {
console.log('组件已挂载');
});
onBeforeUpdate(() => {
console.log('组件更新前');
});
onUpdated(() => {
console.log('组件已更新');
});
onBeforeUnmount(() => {
console.log('组件卸载前');
});
onUnmounted(() => {
console.log('组件已卸载');
});
}
};说明:
- 生命周期钩子
- 组合式 API 中的生命周期
- 执行顺序
- 使用场景
组件开发
组件基础
javascript
// 组件定义
<script setup>
import { ref } from 'vue';
const props = defineProps({
title: {
type: String,
required: true
}
});
const emit = defineEmits(['update']);
const count = ref(0);
function increment() {
count.value++;
emit('update', count.value);
}
</script>
<template>
<div class="my-component">
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<slot></slot>
</div>
</template>
<style scoped>
.my-component {
color: #42b983;
}
</style>
// 组件使用
<template>
<my-component
title="Hello"
@update="handleUpdate"
>
<p>Slot content</p>
</my-component>
</template>说明:
- 组件定义
- Props 定义
- 事件发射
- 插槽使用
- 样式作用域
组件通信
javascript
// 父组件
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const message = ref('Hello from parent');
function handleUpdate(newValue) {
message.value = newValue;
}
</script>
<template>
<child-component
:message="message"
@update="handleUpdate"
/>
</template>
// 子组件
<script setup>
import { ref } from 'vue';
const props = defineProps(['message']);
const emit = defineEmits(['update']);
function updateMessage() {
emit('update', 'Updated message');
}
</script>
<template>
<div>
<p>{{ message }}</p>
<button @click="updateMessage">Update</button>
</div>
</template>
// 依赖注入
<script setup>
import { provide, inject } from 'vue';
// 提供值
provide('message', 'Hello from parent');
// 注入值
const message = inject('message');
</script>说明:
- Props 传递
- 事件发射
- 依赖注入
- 组件通信最佳实践
Teleport
javascript
// 使用 Teleport
<template>
<teleport to="#modal">
<div class="modal">
<h2>Modal Title</h2>
<p>Modal content</p>
<button @click="close">Close</button>
</div>
</teleport>
</template>
<script setup>
function close() {
// 关闭模态框
}
</script>
<style scoped>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
</style>说明:
- Teleport 用途
- 目标选择器
- 样式处理
- 使用场景
状态管理
Pinia
javascript
// store/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
},
async incrementAsync() {
await new Promise(resolve => setTimeout(resolve, 1000));
this.count++;
}
}
});
// 组件中使用
<script setup>
import { useCounterStore } from '@/stores/counter';
const counter = useCounterStore();
// 访问状态
console.log(counter.count);
console.log(counter.doubleCount);
// 调用 action
counter.increment();
counter.incrementAsync();
</script>说明:
- Store 定义
- State 管理
- Getters 计算
- Actions 操作
- 组合式 API 集成
Provide/Inject
javascript
// 提供值
<script setup>
import { provide, ref } from 'vue';
const count = ref(0);
provide('count', count);
function increment() {
count.value++;
}
provide('increment', increment);
</script>
// 注入值
<script setup>
import { inject } from 'vue';
const count = inject('count');
const increment = inject('increment');
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>说明:
- 提供值
- 注入值
- 响应式
- 默认值
路由管理
Vue Router 4
javascript
// 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
});
// 导航守卫
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login');
} else {
next();
}
});
export default router;
// 组件中使用
<script setup>
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route = useRoute();
function goToHome() {
router.push('/');
}
function goToUser(id) {
router.push({ name: 'User', params: { id } });
}
// 访问路由参数
console.log(route.params.id);
</script>说明:
- 路由配置
- 动态路由
- 导航守卫
- 组合式 API 集成
新特性
Suspense
javascript
// 异步组件
<script setup>
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
);
</script>
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
// 异步 setup
<script setup>
async function setup() {
const data = await fetchData();
return { data };
}
</script>说明:
- 异步组件
- 加载状态
- 错误处理
- 使用场景
Fragments
javascript
<template>
<div>First</div>
<div>Second</div>
<div>Third</div>
</template>说明:
- 多根节点
- 不需要包装元素
- 样式处理
- 使用场景
Custom Renderer
javascript
import { createRenderer } from 'vue';
const { render, createApp } = createRenderer({
createElement(type) {
// 创建元素
},
insert(el, parent) {
// 插入元素
},
remove(el) {
// 移除元素
},
patchProp(el, key, prevValue, nextValue) {
// 更新属性
}
});
// 使用自定义渲染器
const app = createApp({
// 应用配置
});说明:
- 自定义渲染器
- 平台适配
- 性能优化
- 使用场景
最佳实践
1. 代码组织
- 使用组合式 API
- 模块化管理
- 遵循命名规范
- 保持组件简洁
2. 性能优化
- 合理使用响应式
- 避免不必要的渲染
- 使用 Suspense
- 懒加载组件
3. 开发技巧
- 使用 Vue Devtools
- 编写单元测试
- 使用 TypeScript
- 遵循 Vue 风格指南
学习资源
官方文档
视频课程
- 慕课网
- 极客时间
- B站技术区
- YouTube 技术频道