vue3知识点:计算属性与监视属性

vue3知识点:计算属性与监视属性_第1张图片

文章目录

  • 二、常用 Composition API
    • 7.计算属性与监视属性
      • 1.computed函数
        • 案例:拼姓名字符串,同vue2计算属性案例类似
        • 完整代码
      • 2.watch函数
        • 案例:计算求和
        • 完整代码
      • 3.watchEffect函数
  • 本人其他相关文章链接

二、常用 Composition API

问题:啥叫“组合式API”?

答案:请看官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html

7.计算属性与监视属性

1.computed函数

vue3知识点:计算属性与监视属性_第2张图片
注意点1:
Vue3中写vue2的计算属性也是可以的,但是不建议混用。

注意点2:

Vue2中computed计算属性如何写

vue3知识点:计算属性与监视属性_第3张图片

Vue3中computed计算属性如何写

vue3知识点:计算属性与监视属性_第4张图片

案例:拼姓名字符串,同vue2计算属性案例类似

vue3知识点:计算属性与监视属性_第5张图片

完整代码

项目目录

vue3知识点:计算属性与监视属性_第6张图片

main.js

//引入的不再是Vue构造函数了,引入的是一个名为createApp的工厂函数
import { createApp } from 'vue'
import App from './App.vue'

//创建应用实例对象——app(类似于之前Vue2中的vm,但app比vm更“轻”)
const app = createApp(App)

//挂载
app.mount('#app')

App.vue

<template>
	<Demo/>
</template>

<script>
	import Demo from './components/Demo'
	export default {
		name: 'App',
		components:{Demo},
	}
</script>

Demo.vue

<template>
	<h1>一个人的信息</h1>
	姓:<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">
</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
			}) */

			//计算属性——完整写法(考虑读和写)
			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>

结果展示:

vue3知识点:计算属性与监视属性_第7张图片

2.watch函数

vue3知识点:计算属性与监视属性_第8张图片
注意点1:

Vue2中watch监视属性如何写

vue3知识点:计算属性与监视属性_第9张图片

Vue3中watch监视属性如何写

vue3知识点:计算属性与监视属性_第10张图片

注意点2:
Vue2中watch作为配置项执行定义一次,不能写多个watch,而vue3中就可以写多个watch配置项,比如监视多个属性变化
vue3知识点:计算属性与监视属性_第11张图片

注意点3:
如果想实现监视多个属性可以配置数组,不用写多个watch,比如如图1,但是既然配置数组了,那我监视的多个属性如何用newValue,oldValue进行接收呢?答案看如图2,它会把监视所有属性的newValue放到一个数组中,同理可得oldValue对应的数组。
vue3知识点:计算属性与监视属性_第12张图片

如图1

在这里插入图片描述

如图2

注意点4:

问题:如果我想实现深度监视或者配置immediate:true放哪里?

答案:watch是可以配置第三个参数的,如图
vue3知识点:计算属性与监视属性_第13张图片
注意点5:
透露个小秘密,这个deep:true在vue3中有点小问题,后续会介绍并补充上。

注意点6:一个坑
如果你用reactive定义的响应式数据交给watch去监视,那么就会发现此处无法正确获取oldValue,但是你用ref定义的就不存在这个问题。举例,用reactive定义输出结果如图,会发现oldValue值不对。

let person = reactive({
	name:'张三',
	age:18
})

/* 
情况三:监视reactive所定义的一个响应式数据的全部属性
1.注意:此处无法正确的获取oldValue
2.注意:强制开启了深度监视(deep配置无效)
*/
 watch(person,(newValue,oldValue)=>{
	console.log('person变化了',newValue,oldValue)
})

vue3知识点:计算属性与监视属性_第14张图片
注意点7:针对注意点6中如果你改为ref定义,会发现控制台打印监视没结果,为啥?因为ref定义的响应式对象数据,最后还是会内部调用reactive,同时ref监视的是person.value才能输出打印,如果像如下代码是不会有任何打印的,除非改成监视person.value,改之后控制台能打印,但是oldValue还是失效的。

let sum = ref(0)
let msg = ref('你好啊')
let person = ref({
	name:'张三',
	age:18
})

//监视错误person
 watch(person,(newValue,oldValue)=>{
	console.log('person变化了',newValue,oldValue)
})
---------------------------------------------------------------
//监视正确 person.value
watch(person.value,(newValue,oldValue)=>{
	console.log('person变化了',newValue,oldValue)
})

总结:
1)如果监听的是ref定义的基础属性(字符串或者数值),那么watch监听的第一个参数不要加.value,因为sum.value代表实际监听的是数值0这个参数,而0你咋监听,你监听的只能是RefImpl对象(或者说监听的是保存数据的一个结构)

正确写法
watch(sum,(newValue,oldValue)=>{
	console.log('sum变了',newValue,oldValue)
},{immediate:true})
--------------------------------------------------------------------------------------------
错误写法
watch(sum.value,(newValue,oldValue)=>{
	console.log('sum变了',newValue,oldValue)
},{immediate:true})

2)监听整个person对象
如果使用ref定义的对象类型数据,那么watch监听的必须是person.value才正确,因为person.value实际是Proxy,也就是ref内部调用reactive封装的Proxy代理对象而如果使用reactive定义的对象类型数据,那么watch监听的必须是person整个对象才是正确的;

思考问题:为啥监听person.value就不用开启深度监视?

答案:监听person.value 对应的是Proxy代理对象,属于内部隐式调用reactive,默认自动开启深度监视,而监听person对应的是RefImpl对象,必须手动开启深度监视

如果使用ref定义的对象类型数据

let person = ref({
	name:'张三',
	age:18,
	job:{
		j1:{
			salary:20
		}
	}
})

//正确写法方式1:第一种监听person.value
watch(person.value,(newValue,oldValue)=>{
	:console.log('person变化了',newValue,oldValue)
}) 
------------------------------------------------------------------------------------------
//正确写法方式2:第二种监听person,但是开启深度监视deep:true
watch(person,(newValue,oldValue)=>{
	:console.log('person变化了',newValue,oldValue)
},{deep:true}) 

如果使用reactive定义的对象类型数据直接监视person对象就行,默认开启深度监视,所以不用设置deep:true

let person = ref({
	name:'张三',
	age:18,
	job:{
		j1:{
			salary:20
		}
	}
})

watch(person,(newValue,oldValue)=>{
	:console.log('person变化了',newValue,oldValue)
}) 

3)监听person对象的某个属性
推荐用reactive封装对象类型数据,不推荐ref封装对象类型数据。

所以这里咱们考虑使用reactive定义的对象类型数据,如果监听的是person对象中的基础属性,比如监听name属性(字符串或者数值),那么监听第一个参数请写成函数

//情况五:监视reactive所定义的一个响应式数据中的某些属性
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
	console.log('person的name或age变化了',newValue,oldValue)
})

如果监听的是person对象中job对象中的某个属性,那么必须设置{deep:true},否则深度监听无效

这是正确的
watch(()=>person.job,(newValue,oldValue)=>{
	 	console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
--------------------------------------------------------------------------------------------
这是错误的
watch(()=>person.job,(newValue,oldValue)=>{
	 	console.log('person的job变化了',newValue,oldValue)
}) 

注意点8:
用reactive定义的对象有多层嵌套的话,那么vue3默认开启深度监视,而vue2必须开启deep:true后才能识别深度监视。

注意点9:(和注意点12进行对比记忆)
用reactive定义的响应式对象数据,强制开启深度监视,无法关闭deep配置(前提是watch监视的是reactive定义的整个对象,如果监视的是person对象中job属性中的salary那就不好使了)
vue3知识点:计算属性与监视属性_第15张图片

注意点10:
监视reactive定义的一个响应式数据对象中的某个属性,第一个参数必须写成函数且返回值(否则写别的无效),例如()=>person.name代表只监视name属性变化,这样写这个oldValue就是生效的。
vue3知识点:计算属性与监视属性_第16张图片

注意点11:

问题:针对注意点10,如果我想监视多个属性呢?

答案:配置成数组,虽然写起来有点重复,但就得这么配置
vue3知识点:计算属性与监视属性_第17张图片

注意点12:(和注意点9进行对比记忆)
如下代码如果想实现监听person.job,但是点击涨薪按钮后修改的是job里的salary发现没监听到?错误展示效果看如图:watch监视的特殊情况不生效案例.gif
vue3知识点:计算属性与监视属性_第18张图片

watch监视的特殊情况不生效案例.gif

错误原因在于没开启deep:true深度监视

let person = reactive({
	name:'张三',
		age:18,
		job:{
			j1:{
				salary:20
			}
		}
	})

//特殊情况
//错误写法,未配置deep:true
 watch(()=>person.job,(newValue,oldValue)=>{
	console.log('person的job变化了',newValue,oldValue)
}})
------------------------------------------------------------------
//正确写法,配置deep:true
 watch(()=>person.job,(newValue,oldValue)=>{
	console.log('person的job变化了',newValue,oldValue)
}},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效 

注意点13:
项目中使用情况三方式多些,此处oldValue是无效的,但是如果你非想使用oldValue,那么可以把person中需要监听oldValue的属性单独用ref去包裹设置,因为ref方式中oldValue是生效的。

注意点14:
总结:坑其实有3个
第1个坑:监视reactive所定义的一个响应式数据对象person,无法正确的获取oldValue,且强制开启了深度监视(deep配置无效)
第2个坑:监视person对象中的name属性,比如情况四,那么oldValue就是好使的
第3个坑:针对特殊情况,如果监视person.job,而你修改的是person.job里的嵌套属性salary,那么必须开启深度监视deep:true后才能监听到。

案例:计算求和

vue3知识点:计算属性与监视属性_第19张图片

完整代码

项目目录

vue3知识点:计算属性与监视属性_第20张图片

main.js

//引入的不再是Vue构造函数了,引入的是一个名为createApp的工厂函数
import { createApp } from 'vue'
import App from './App.vue'

//创建应用实例对象——app(类似于之前Vue2中的vm,但app比vm更“轻”)
const app = createApp(App)

//挂载
app.mount('#app')

App.vue

<template>
	<Demo/>
</template>

<script>
	import Demo from './components/Demo'
	export default {
		name: 'App',
		components:{Demo},
	}
</script>

Demo.vue

<template>
	<h2>当前求和为:{{sum}}</h2>
	<button @click="sum++">点我+1</button>
	<hr>
	<h2>当前的信息为:{{msg}}</h2>
	<button @click="msg+='!'">修改信息</button>
	<hr>
	<h2>姓名:{{person.name}}</h2>
	<h2>年龄:{{person.age}}</h2>
	<h2>薪资:{{person.job.j1.salary}}K</h2>
	<button @click="person.name+='~'">修改姓名</button>
	<button @click="person.age++">增长年龄</button>
	<button @click="person.job.j1.salary++">涨薪</button>
</template>

<script>
	import {ref,reactive,watch} from 'vue'
	export default {
		name: 'Demo',
		setup(){
			//数据
			let sum = ref(0)
			let msg = ref('你好啊')
			let person = reactive({
				name:'张三',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})

			//情况一:监视ref所定义的一个响应式数据
			/* watch(sum,(newValue,oldValue)=>{
				console.log('sum变了',newValue,oldValue)
			},{immediate:true}) */

			//情况二:监视ref所定义的多个响应式数据
      watch([sum,msg],(newValue,oldValue)=>{
				console.log('sum或msg变了',newValue,oldValue)
			},{immediate:true})

			/* 
				情况三:监视reactive所定义的一个响应式数据的全部属性
						1.注意:此处无法正确的获取oldValue
						2.注意:强制开启了深度监视(deep配置无效)
			*/
      // watch(person,(newValue,oldValue)=>{
			// 	console.log('person变化了',newValue,oldValue)
			// },{deep:false}) //此处的deep配置无效

			//情况四:监视reactive所定义的一个响应式数据中的某个属性
			/* watch(()=>person.name,(newValue,oldValue)=>{
				console.log('person的name变化了',newValue,oldValue)
			})  */

			//情况五:监视reactive所定义的一个响应式数据中的某些属性
			/* watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
				console.log('person的name或age变化了',newValue,oldValue)
			})  */

			//特殊情况
			/* watch(()=>person.job,(newValue,oldValue)=>{
				console.log('person的job变化了',newValue,oldValue)
			},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效 */


			//返回一个对象(常用)
			return {
				sum,
				msg,
				person
			}
		}
	}
</script>

结果展示:

vue3知识点:计算属性与监视属性_第21张图片

3.watchEffect函数

vue3知识点:计算属性与监视属性_第22张图片
注意点1:

问题:watchEffect和watch区别?

答案:
1)watchEffect不告诉你它监视谁,回调中用到哪个属性我就自动监视哪个属性,跟watch函数区别是没有第一个参数
2)watchEffect默认开启立即执行属性immediate:true和深度监视deep:true

注意点2:

问题:watchEffect和computed区别?

答案:computed注重return的返回值,而watchEffect更注重过程

本人其他相关文章链接

1.《vue3第二章》常用组合式 Composition API,包括setup、ref函数、reactive函数、vue3.0中的响应式原理、计算属性与监听属性
2.vue3知识点:setup
3.vue3知识点:ref函数
4.vue3知识点:reactive函数
5.vue3知识点:Vue3.0中的响应式原理和 vue2.x的响应式
6.vue3知识点:reactive对比ref
7.vue3知识点:计算属性与监视属性
8.vue3知识点:生命周期
9.vue3知识点:自定义hook函数
10.vue3知识点:toRef函数和toRefs函数

你可能感兴趣的:(Vue3专栏,前端,vue3,vue,计算属性,监视属性)