目录
一、组合式 API 的使用
1.1、watch 函数
1.2、watchEffect 函数
1.3、toRef 和 toRefs
1.3.1、toRef
1.3.2、toRefs
1.4、vue3 的声明周期
一、组合式 API 的使用
1.1、watch 函数
与 vue2.x 中的 watch 配置功能一致,但是多了一些坑:
这是我当前的 vue 版本
- 监视 reactive 定义的响应式数据时:oldValue 无法正确获取
- 监视 reactive 定义的响应式数据中某个属性时:deep 配置有效.
Ps:我目前使用的 vue3 的版本没有以上问题!!!
这里我来列出几种情况:
a)监视 ref 所定义的响应式数据
<template><h2>当前和为: {{ sum }}</h2><button @click="sum++">点我 + 1</button>
</template><script>
import { ref, watch } from "vue";
export default {name: "App",setup() {let sum = ref(0);watch(sum, (newValue, ordValue) => {console.log("sum变了", newValue, ordValue);});return {sum,};},
};
</script>
监视没有问题,如下:
b)监视 ref 定义的多个响应式数据(只要其中一个变,就会触发监视事件)
<template><h2>当前和为: {{ sum }}</h2><h2>{{ msg }}</h2><button @click="sum++">点我 + 1</button><button @click="msg += '!'">点我 + !</button>
</template><script>
import { ref, watch } from "vue";
export default {name: "App",setup() {let sum = ref(0);let msg = ref("你好呀");//情况二watch([sum, msg], (newValue, oldValue) => {console.log("sum 或 msg 变了", newValue, oldValue);});return {sum,msg,};},
};
</script>
先点三下 “点我 + 1”、再点三下 “点我 + !”,效果如下:
c)监视 reactive 所定义的一个响应式数据的全部属性,无法正确的获取 oldValue
若没有配置 deep,默认开启深度监视(老版本的 vue3 强制开启深度监视,无法修改,我当前使用的版本已修改该问题).
<template><h2>一个人的信息</h2><div>{{ person.name }}</div><div>{{ person.age }}</div><div>{{ person.a.b.c }}</div><button @click="person.name = 'lyj'">修改姓名</button><button @click="person.age += 1">修改年龄</button><button @click="person.a.b.c += 100">修改a.b.c</button>
</template><script>
import { reactive, ref, watch } from "vue";
export default {name: "App",setup() {let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});//情况三watch(person,(newValue, oldValue) => {console.log("person变化了", newValue, oldValue);},);return {person,};},
};
</script>
依次点击按钮,效果如下:
若设置 deep 为 false ,则点击 “修改 a.b.c ” 无效,如下:
<template><h2>一个人的信息</h2><div>{{ person.name }}</div><div>{{ person.age }}</div><div>{{ person.a.b.c }}</div><button @click="person.name = 'lyj'">修改姓名</button><button @click="person.age += 1">修改年龄</button><button @click="person.a.b.c += 100">修改a.b.c</button>
</template><script>
import { reactive, ref, watch } from "vue";
export default {name: "App",setup() {let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});//情况三watch(person,(newValue, oldValue) => {console.log("person变化了", newValue, oldValue);},{ deep: false } //此处 deep 配置有效!!版本更新,修复了之前无效的问题);return {person,};},
};
</script>
d)监视 reactive 所定义的一个响应式数据中的某个属性,这样可以解决上述请款三无法正确显示 oldValue 的问题
这里写法上和之前有点差异,第一个参数返回的是一个箭头函数.
<template><h2>一个人的信息</h2><div>{{ person.name }}</div><div>{{ person.age }}</div><div>{{ person.a.b.c }}</div><button @click="person.name = 'lyj'">修改姓名</button><button @click="person.age += 1">修改年龄</button><button @click="person.a.b.c += 100">修改a.b.c</button>
</template><script>
import { reactive, ref, watch } from "vue";
export default {name: "App",setup() {let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});//情况四watch(() => person.name,(newValue, oldValue) => {console.log("person 的 name 变化了", newValue, oldValue);});return {person,};},
};
</script>
点就 修改姓名 按钮,效果如下:
e)监视 reactive 所定义的一个响应式数据中的某些属性(这种方式可以用来解决监视 reactive 后 oldValue 变化的问题).
<template><h2>一个人的信息</h2><div>{{ person.name }}</div><div>{{ person.age }}</div><div>{{ person.a.b.c }}</div><button @click="person.name = 'lyj'">修改姓名</button><button @click="person.age += 1">修改年龄</button><button @click="person.a.b.c += 100">修改a.b.c</button>
</template><script>
import { reactive, ref, watch } from "vue";
export default {name: "App",setup() {let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});//情况五watch([() => person.name, () => person.age], (newValue, oldValue) => {console.log("person 的 name 或 age 变化了", newValue, oldValue);});return {person,};},
};
</script>
依次点击 修改姓名 和 修改年龄,效果如下:
f)特殊情况:当监视的是 reactive 定义的对象中的某个属性对象或者当前对象,并且第一个参数返回的是 回调方法,deep也会生效,默认非深层监视.
1.2、watchEffect 函数
watchEffect 的参数就是一个回调.
不用指明监视的是哪个属性,只要监视的回调中用到哪个属性发生变化了,就会重新执行回调(挂载的时候也会执行一次).
<template><h2>一个人的信息</h2><div>{{ person.name }}</div><div>{{ person.age }}</div><div>{{ person.a.b.c }}</div><button @click="person.name = 'lyj'">修改姓名</button><button @click="person.age += 1">修改年龄</button><button @click="person.a.b.c += 100">修改a.b.c</button>
</template><script>
import { reactive, watchEffect } from "vue";
export default {name: "App",setup() {let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});watchEffect(() => {const test1 = person.name;const test2 = person.a.b.c;console.log("watchEffect 回调执行了");});return {person,};},
};
</script>
刚开始组件挂载的时候会执行一次,之后分别点击 修改姓名 和 修改 a.b.c ,又会执行两次,效果如下:
Ps:默认 deep: false,因此如果 watchEffect 中使用 person.a 的话,修改 person.a.b.c 是不会重新执行回调的.
1.3、toRef 和 toRefs
1.3.1、toRef
将指定的属性通过 toRef 就可以创建一个 ref 对象.
通俗来讲,是对源对象的属性的浅拷贝,并且将源对象对应的属性改成响应式的.
为什么要使用它?例如以下场景:
let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});
a)要给模板中展示 person 的所有属性很麻烦,每次都要 person. 的方式才能获取到对应的属性,因此可能就有人会这样操作:
let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});return {person,name: person.name, //模板中可以直接使用 name 表示 person.nameage: person.age, //同理};
b)但是上述这种方式返回的数据不是响应式的呀,因此,就有人想到了以下方式
let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});return {person,name: ref(person.name), //模板中可以直接使用 name 表示 person.nameage: ref(person.age), //同理};
c)虽然实现了响应式,但是这相当于是重新创建了一个新的 ref 对象,对这些数据的修改不会影响源数据,因此就需要使用 toRef 了~
let person = reactive({name: "cyk",age: 18,a: {b: {c: 666,},},});return {person,name: toRef(person, "name"), //模板中可以直接使用 name 表示 person.nameage: toRef(person, "age"), //同理};
1.3.2、toRefs
和 toRef 的功能一致,但是它可以直接将一个对象中的所有属性都变成响应式的,语法:toRefs(person).
return {...toRefs(person),};
1.4、vue3 的声明周期
a)vue3 中可以继续使用 vue2 中的生命周期钩子,但有两个被更名.
- beforeDestory 改名为 beforeUnmount.
- destroyed 改名为 unmounted.
b)vue3 中也提供了 Composition API 形式的生命周期钩子,与 vue2 中的钩子对应关系如下:
案例如下:
App 父组件定义如下
<template><button @click="isShowUser = !isShowUser">切换隐藏/显示</button><User v-if="isShowUser" />
</template><script>
import { ref } from "vue";
import User from "./views/User.vue";
export default {name: "App",components: { User },setup() {let isShowUser = ref(true);return {isShowUser,};},
};
</script>
User 子组件如下:
<template><h2>求和: {{ sum }}</h2><button @click="sum++">点我 + 1</button>
</template><script>
import {ref,onBeforeMount,onBeforeUnmount,onBeforeUpdate,onMounted,onUnmounted,onUpdated,
} from "vue";
export default {name: "User",setup() {let sum = ref(0);// vue3 中可以通过组合式 API 的形式取使用声明周期的钩子onBeforeMount(() => {console.log("-------onBeforeMount-------");});onMounted(() => {console.log("-------onMounted-------");});onBeforeUpdate(() => {console.log("-------onBeforeUpdate-------");});onUpdated(() => {console.log("-------onUpdated-------");});onBeforeUnmount(() => {console.log("--------onBeforeUnmount------");});onUnmounted(() => {console.log("--------onUnmounted------");});return {sum,};},
};
</script>
使用效果如下: