视频教程:BV1W1421173W
视频链接:BV1W1421173W
发布日期:2024-05-28
视频时长:26:18
播放量:10.5万
所属合集:零基础AI全栈开发系列
视频概要
Vue3 Composition API的深入教学。详细讲解ref/reactive响应式系统、computed计算属性、watch侦听器、生命周期钩子、单文件组件结构(.vue)、组件通信等核心内容。是上一集《十分钟入门Vue》的深度补充版。
知识点清单
A. Composition API 核心API
| API | 作用 | 使用场景 |
|---|---|---|
ref() | 创建基本类型的响应式数据 | 字符串、数字、布尔值 |
reactive() | 创建对象类型的响应式数据 | 复杂对象、数组 |
computed() | 计算属性,基于响应式数据自动计算并缓存 | 派生状态 |
watch() | 侦听器,监听数据变化执行副作用 | 异步请求、日志 |
watchEffect() | 自动追踪依赖的侦听器 | 自动收集依赖 |
onMounted() | 生命周期:组件挂载到DOM后执行 | 初始化数据请求 |
onUpdated() | 生命周期:数据更新后执行 | 响应DOM变化 |
onUnmounted() | 生命周期:组件卸载前执行 | 清理定时器、取消订阅 |
B. ref vs reactive 详解
import { ref, reactive } from 'vue';
// ref: 基本类型 → 通过 .value 访问和修改
const count = ref(0);
console.log(count.value); // 0
count.value++; // 修改必须用 .value
// reactive: 对象类型 → 直接访问属性
const state = reactive({
name: "张三",
age: 18,
todos: []
});
console.log(state.name); // 张三
state.todos.push("新任务"); // 直接修改
state.age = 19; // 直接修改
| 对比项 | ref() | reactive() |
|---|---|---|
| 适用类型 | 基本类型 + 对象 | 仅对象/数组 |
| 访问方式 | .value | 直接访问属性 |
| 模板中使用 | 自动解包,无需 .value | 直接使用 |
| 重新赋值 | ref.value = 新值 ✅ | 不可整体替换 ❌ |
| 解构 | 保持响应式 | 解构后丢失响应式 |
C. 计算属性 computed
import { ref, computed } from 'vue';
const firstName = ref("张");
const lastName = ref("三");
// 自动追踪依赖,依赖不变则缓存结果(性能优化)
const fullName = computed(() => {
return firstName.value + lastName.value;
});
console.log(fullName.value); // 张三
// 可写的计算属性
const fullNameRW = computed({
get: () => firstName.value + lastName.value,
set: (val) => {
firstName.value = val[0];
lastName.value = val.slice(1);
}
});
computed与methods的区别:computed会缓存结果,只有依赖变化才重新计算;methods每次调用都重新执行。
D. 侦听器 watch
import { ref, watch, watchEffect } from 'vue';
const keyword = ref("");
// watch: 监听指定数据
watch(keyword, (newVal, oldVal) => {
console.log(`搜索词从 "${oldVal}" 变为 "${newVal}"`);
// 可在此发起搜索请求
});
// watch: 监听多个数据
const page = ref(1);
watch([keyword, page], ([newK, newP], [oldK, oldP]) => {
console.log("关键词或页码变化了");
});
// watchEffect: 自动追踪依赖
watchEffect(() => {
console.log("当前搜索:", keyword.value, "第", page.value, "页");
// 自动追踪内部用到的所有响应式数据
});
E. 生命周期钩子
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue';
// 创建前后的生命周期顺序:
// setup() → onBeforeMount → onMounted → onBeforeUpdate → onUpdated → onBeforeUnmount → onUnmounted
onMounted(() => {
console.log("组件已挂载到DOM");
// 最常用的钩子:在这里发起初始数据请求
});
onUpdated(() => {
console.log("组件数据已更新");
});
onUnmounted(() => {
console.log("组件即将卸载");
// 清理定时器、取消事件监听、取消网络请求等
});
F. 单文件组件结构(.vue)
<template>
<!-- HTML模板 -->
<div class="my-component">
<h1>{{ title }}</h1>
<p>计数:{{ count }}</p>
<p>双倍:{{ doubleCount }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
// JavaScript逻辑(Composition API语法糖)
import { ref, computed } from 'vue';
const title = ref("我的组件");
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
const increment = () => {
count.value++;
};
</script>
<style scoped>
/* CSS样式(scoped表示仅作用于当前组件,不污染全局) */
.my-component {
padding: 20px;
text-align: center;
}
</style>
<script setup>是Vue3的语法糖,比传统的export default { setup() {...} }更简洁,推荐使用。
G. 组件通信
<!-- 父组件 -->
<template>
<ChildComponent
:msg="parentMsg"
@update="handleUpdate"
/>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './Child.vue';
const parentMsg = ref("来自父组件的消息");
const handleUpdate = (val) => {
console.log("子组件传来的值:", val);
};
</script>
<!-- 子组件 Child.vue -->
<template>
<div>
<p>{{ msg }}</p>
<button @click="$emit('update', '新数据')">通知父组件</button>
</div>
</template>
<script setup>
// defineProps: 接收父组件传来的数据
defineProps({
msg: String
});
// defineEmits: 向父组件发送事件
defineEmits(['update']);
</script>
H. Vue2 vs Vue3 完整对比
| 特性 | Vue2 (Options API) | Vue3 (Composition API) |
|---|---|---|
| 数据声明 | data() 返回对象 | ref() / reactive() |
| 方法 | methods: {} | 普通函数 |
| 计算属性 | computed: {} | computed() |
| 侦听器 | watch: {} | watch() / watchEffect() |
| 生命周期 | mounted() 等钩子 | onMounted() 等钩子函数 |
| 代码组织 | 按选项类型分组 | 按逻辑功能分组 |
| 类型支持 | 较弱 | 原生支持TypeScript |
| 性能 | 较好 | 更好(Tree-shaking、Proxy) |
| 组件复用 | Mixins | Composables(组合函数) |
常见问题
| 问题 | 解答 |
|---|---|
| ref为什么要用.value? | 因为JS中基本类型赋值是拷贝,需要包装成对象才能保持响应式 |
<script setup> 是什么? | Vue3的语法糖,简化Composition API写法,变量直接在模板中可用 |
| scoped是什么意思? | 样式只作用于当前组件,不影响其他组件 |
| computed和watch怎么选? | 派生数据用computed(如拼接全名),副作用用watch(如发请求) |
| 组件通信怎么实现? | 父传子用props,子传父用emit,兄弟组件用状态管理(Pinia) |
| Composition API和Options API哪个好? | Composition API代码组织更灵活,推荐新项目使用 |
前置知识检查
- [x] 理解Vue的基本概念(响应式、指令)
- [x] 了解JavaScript的函数和对象
- [x] 看过上一集《十分钟入门Vue》
学习建议
ref和reactive是Vue3最核心的两个API,务必理解区别<script setup>是推荐写法,比传统的export default更简洁- 不理解生命周期没关系,学到后面Node.js对接时自然会用到
onMounted - computed和watch的区别是面试高频题,务必搞清楚