一、computed 函数
1. 计算属性 — 简写(不考虑计算属性被修改的情况)
- 在 setup 中定义 person 对象,通过 reactive 设置成响应式
- 给 person 添加计算属性,名为 fullName,返回全名
<template> <div> <h3>一个人的信息</h3> 姓:<input type="text" v-model="person.firstName" /><br /> 名:<input type="text" v-model="person.lastName" /><br /> <span>全名:{{ person.fullName }}</span><br/> </div> </template> <script> import { reactive, computed } from "vue"; export default { name: "Demo", setup() { // 数据 let person = reactive({ firstName: "张", lastName: "三", }); // 计算属性——简写(没有考虑计算属性被修改的情况) person.fullName = computed(()=>{ return person.firstName + '-' + person.lastName }) // 返回一个对象 return { person, }; }, }; </script>
计算属性显示全名:
2. 计算属性 — 完整写法(考虑计算属性被修改的情况)
- 动态修改 input 框,响应式变化
- 完整写法,要在计算属性内配置 get 和 set
- get 里面是返回值,set 里面给对应属性赋值
<template> <div> <h3>一个人的信息</h3> 姓:<input type="text" v-model="person.firstName" /><br /> 名:<input type="text" v-model="person.lastName" /><br /> <span>全名:{{ person.fullName }}</span><br/> 全名:<input type="text" v-model="person.fullName"> </div> </template> <script> import { reactive, computed } from "vue"; export default { name: "Demo", setup() { // 数据 let person = reactive({ firstName: "张", lastName: "三", }); // 计算属性——完整写法(考虑读和写) person.fullName = computed({ get(){ return person.firstName + '-' + person.lastName }, set(value){ const nameArr = value.split('-') person.firstName = nameArr[0] person.lastName = nameArr[1] } }) // 返回一个对象 return { person, }; }, }; </script>
效果如下:
二、watch 函数
1. 监视 ref 所定义的一个响应式数据
- 第一个参数:监听的是谁
- 第二个参数:监视的回调
- 第三个参数:监视的配置 => 立即执行(页面一经加载就执行一次)
<template> <div> <h3>当前求和为:{{ sum }}</h3> <button @click="sum++">点我+1</button> </div> </template> <script> import { ref, watch } from "vue"; export default { name: "Demo", setup() { // 数据 let sum = ref(0); // 情况一:监视ref所定义的一个响应式数据 watch(sum, (newValue, oldValue) => { console.log("sum变了", newValue, oldValue); }, {immediate: true}); // 返回一个对象 return { sum, }; }, }; </script>
监听 ref 所定义的一个响应式数据:
2. 监视 ref 所定义的多个响应式数据
- 监视多个响应式数据:sum 和 msg
- sum 每次 +1,msg 每次多一个 !
- 监听多个数据:用 [] 括起来
<template> <div> <h3>当前求和为:{{ sum }}</h3> <button @click="sum++">点我+1</button> <hr/> <h3>当前的信息为:{{ msg }}</h3> <button @click="msg+='!'">修改信息</button> </div> </template> <script> import { ref, watch } from "vue"; export default { name: "Demo", setup() { // 数据 let sum = ref(0); let msg = ref('你好啊') // 情况二:监视ref所定义的多个响应式数据 watch([sum, msg], (newValue, oldValue)=>{ console.log('sum或msg变了', newValue, oldValue); }) // 返回一个对象 return { sum, msg, }; }, }; </script>
按钮分别点击两次:
3. 监视 reactive 所定义一个响应式数据的全部数据
- 监视 reactive 定义的响应式数据时:oldValue 无法正确获取
- 监视 reactive 定义的响应式数据时:强制开启了深度监视(deep 配置失效)
<template> <div> <h3>姓名:{{person.name}}</h3> <h3>年龄:{{person.age}}</h3> <button @click="person.name+='~'">修改姓名</button> <button @click="person.age++">增长年龄</button> </div> </template> <script> import { reactive, watch } from "vue"; export default { name: "Demo", setup() { // 数据 let person = reactive({ name: '张三', age: 18, }) /* 情况三:监视reactive所定义一个的响应式数据的全部数据 1.注意:此处无法正确的获取oldValue 2.注意:强制开启了深度监视(即deep配置无效) */ watch(person, (newValue, oldValue)=>{ console.log('person变化了', newValue, oldValue); }, {deep: true}) // 返回一个对象 return { person }; }, }; </script>
都是显示的 newValue:
4. 监视 reactive 所定义一个响应式数据中的某个属性
- 要写成函数的形式 () => person.age
<template> <div> <h3>姓名:{{person.name}}</h3> <h3>年龄:{{person.age}}</h3> <button @click="person.name+='~'">修改姓名</button> <button @click="person.age++">增长年龄</button> </div> </template> <script> import { reactive, watch } from "vue"; export default { name: "Demo", setup() { // 数据 let person = reactive({ name: '张三', age: 18, }) // 情况四:监视reactive所定义一个响应式数据中的某个属性 watch(() => person.age, (newValue, oldValue)=>{ console.log('person的age变化了', newValue, oldValue); }) // 返回一个对象 return { person }; }, }; </script>
某个属性:oldValue 可以获取:
5. 监视 reactive 所定义一个的响应式数据中的某些属性
- 用 [] 包裹起来,写成数组的形式
- 多个属性分别用函数形式表示
<template> <div> <h3>姓名:{{person.name}}</h3> <h3>年龄:{{person.age}}</h3> <button @click="person.name+='~'">修改姓名</button> <button @click="person.age++">增长年龄</button> </div> </template> <script> import { reactive, watch } from "vue"; export default { name: "Demo", setup() { // 数据 let person = reactive({ name: '张三', age: 18, }) // 情况五:监视reactive所定义一个的响应式数据中的某些属性 watch([() => person.name, () => person.age], (newValue, oldValue) => { console.log('person的name或age变化了', newValue, oldValue); }) // 返回一个对象 return { person }; }, }; </script>
依次点击修改姓名,增长年龄:
6. 监视 reactive 定义的响应式数据中某个属性时:deep配置有效。
- 若设置 deep: false ,则控制台没有输出
- 监视 reactive 定义的响应式数据中某个属性时:deep配置有效。
<template> <div> <h3>姓名:{{person.name}}</h3> <h3>年龄:{{person.age}}</h3> <h3>薪资:{{person.job.j1.salary}}K</h3> <button @click="person.name+='~'">修改姓名</button> <button @click="person.age++">增长年龄</button> <button @click="person.job.j1.salary++">增加薪资</button> </div> </template> <script> import { reactive, watch } from "vue"; export default { name: "Demo", setup() { // 数据 let person = reactive({ name: '张三', age: 18, job: { j1:{ salary: 20 } } }) // 特殊情况:监视reactive定义的响应式数据中某个属性时:deep配置有效。 watch(() => person.job, (newValue, oldValue) => { console.log('person的job变化了', newValue, oldValue); }, {deep: false}) // 返回一个对象 return { person }; }, }; </script>
开启深度监视:
三、watchEffect 函数
1. 对比 watch 和 watchEffect
- watch 的套路:既要指明监视的属性,也要指明监视的回调
- watchEffect 的套路:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
2. watchEffect 类似于 computed
- 但 computed 注重的计算出来的值(回调函数的返回值),所以必须要写返回值
- 而 watchEffect 更注重的是过程(回调函数的函数体),所以不用写返回值
当点击 点我+1 和 增加薪资 时会被监视:
<template> <div> <h3>当前求和为:{{ sum }}</h3> <button @click="sum++">点我+1</button> <hr/> <h3>薪资:{{person.job.j1.salary}}K</h3> <button @click="person.job.j1.salary++">增加薪资</button> </div> </template> <script> import { ref, reactive, watchEffect } from "vue"; export default { name: "Demo", setup() { // 数据 let sum = ref(0); let person = reactive({ job: { j1:{ salary: 20 } } }) watchEffect(()=>{ const x1 = sum.value const x2 = person.job.j1.salary console.log('watchEffect所指定的回调执行了', x1, x2); }) // 返回一个对象 return { sum, msg, person }; }, }; </script>
第一个按钮点击一次,第二个按钮点击两次:
四、生命周期钩子
1. 官方图解
2. 通过配置项的形式使用生命周期钩子
- setup 就是一个配置项,通过配置项的形式使用钩子
- 下面对生命周期钩子进行简单测试
App.vue
<template> <div> <button @click="isShowDemo = !isShowDemo">切换隐藏/显示</button> <Demo v-if="isShowDemo" /> </div> </template> <script> import { ref } from "vue"; import Demo from "./components/Demo.vue"; export default { name: "App", components: { Demo }, setup() { let isShowDemo = ref(true); return { isShowDemo }; }, }; </script>
Demo.vue
<template> <div> <h3>当前求和为:{{ sum }}</h3> <button @click="sum++">点我+1</button> </div> </template> <script> import { ref } from "vue"; export default { name: "Demo", setup() { // 数据 let sum = ref(0); // 返回一个对象 return { sum }; }, // 通过配置项的形式使用生命周期钩子 beforeCreate(){ console.log('---beforeCreate---'); }, created(){ console.log('---created---'); }, beforeMount(){ console.log('---beforeMount---'); }, mounted(){ console.log('---mounted---'); }, beforeUpdate(){ console.log('---beforeUpdate---'); }, updated(){ console.log('---updated---'); }, beforeUnmount(){ console.log('---beforeUnmount---'); }, unmounted(){ console.log('---unmounted---'); } }; </script>
页面一加载:
点击求和:
点击切换/隐藏显示:
3. 通过组合式API的形式去使用生命周期钩子
- 把生命周期钩子写入 setup 配置项里面
<template> <div> <h3>当前求和为:{{ sum }}</h3> <button @click="sum++">点我+1</button> </div> </template> <script> import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from "vue"; export default { name: "Demo", setup() { // 数据 let sum = ref(0); // 通过组合式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>
不积跬步无以至千里 不积小流无以成江海