vue计算属性computed和侦听器watch的使用

1、计算属性computed

对于复杂逻辑我们可以使用计算属性进行处理;

1.1、vue2计算属性介绍

bash 复制代码
//vue2 index.vue
<template>
	<div class="index-main">
		<P>我是首页{{title}}</p>
		<!-- Hello -->
		<div>{{msg}}</div>
		<!-- olleH -->
		<div>{{reversedMeg}}</div>
	</div>
</template>
<script>
export default {
  name: 'Home',
  data(){
    return {
         title:'计算属性和侦听器',
         msg:'hello',
         count:1
    }
  },
  computed:{
  	//仅读取
  	reversedMeg: function(){
  		return this.msg.split('').reverse().join('');
  	}
  },
  mounted(){}
}
</script>

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:

建议:只读取,不修改;以下为html中创建vue实例修改计算属性时对原值的影响

bash 复制代码
//vue2  index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<div>a: {{a}}</div>
			<div>aPlus: {{aPlus}}</div>
		</div>
		script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
		<script>
			var vm = new Vue({
				el: '#app',
				components: {},
				data:{
					a: 3
				},
				computed:{
					aPlus: {
						get: function(){
							return this.a + 5
						},
						set: function(newValue){
							console.log('newValue',newValue);
							this.a = newValue - 2
						}
					}
				},
				mounted(){},
				methods:{}
			})
			console.log('vm',vm);
			//运行此代码后,a的值将变为0
			vm.aPlus = 2;
		</script>
	</body>
</html>

1.2、vue3计算属性介绍

bash 复制代码
//vue3 index.vue
<script setup>
import { ref,reactive,computed  } from 'vue';
const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

function countHandle(){
	author.books = [];
	//清空书籍时,hasBook会实时更改为No
}

const hasBook= computed(()=>{
	return author.books.length>0 ? 'Yes' : 'No'
})
/*
定义方法实现上述计算属性结果
function hasBookHandle(){
	return author.books.length>0 ? 'Yes' : 'No'
}
*/
</script>
<template>
<div>是否有书籍:<span>{{hasBook}}</span></div>
<!-- <div>是否有书籍:<span>{{ hasBookHandle() }}</span></div> -->
<button @click="countHandle()">清空书籍</button>
</template>

可写计算属性,避免直接修改计算属性

计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到"可写"的属性,你可以通过同时提供 getter 和 setter 来创建:

bash 复制代码
<script setup>
import { ref,computed  } from 'vue';
const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  /* getter 计算属性的 getter 应只做计算;不要改变其他状态、在 getter 中做异步请求或者更改 DOM */
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // 注意:我们这里使用的是解构赋值语法
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})

const full = computed(()=>{
	return firstName.value + ' ' + lastName.value
})

function buttonClick(){
	fullName.value = 'Jone Sum'; //无警告及报错
	// full.value = 'Jone Sum';//警告提示:computed value is readonly
}
</script>
<template>
	<div>全名:<span>{{fullName}}</span></div>
	  <div>全名:<span>{{full}}</span></div>
	  <button @click="buttonClick">修改全名</button>
</template>

setter 会被调用而 firstName 和 lastName 会随之更新。

bash 复制代码
//vue3 index.vue
<script setup>
import { ref,computed  } from 'vue';
</script>
<template>
</template>

2、侦听器

2.1、vue2

当需要在数据变化时执行异步或开销较大的操作时建议使用侦听器;

bash 复制代码
//vue2 index.vue
<template>
	<div class="index-main">
		<div>count: {{count}}</div>
		<div>countDouble: {{countDouble}}</div>
		<input v-model="inputVal" placeholder="请输入修改值"/>
		<button @click="changeHandle">修改</button>
	</div>
</template>
<script>
export default {
  name: 'Home',
  data(){
    return {
         count: 3,
         inputVal:''
    }
  },
  computed:{
  	countDouble: function(){
		return this.count * 2
	}
  },
  watch:{
  	/*监听count的变化,点击按钮时,会触发此事件,可获取新修改值及旧值*/
	count(newVal,oldVal){
		console.log('newVal',newVal);
		console.log('oldVal',oldVal);
	}
  },
  methods(){
  	/*修改count值*/
  	changeHandle(){
		this.count = this.inputVal;
	},
  }
}
</script>

vue2中depp及immediate的用法

bash 复制代码
//obj:{a:1,b:2}
watch:{
	//immediate设置后 侦听开始之后被立即调用
	//设置immediate,不调取changeHandle方法也会触发count侦听器
	count:{
		handler: function(newVal,oldVal){
			console.log('newVal',newVal);
			this.sum = this.count*1 + 5
		},
		immediate: true
	},
	//调取changeHandle方法时sum修改,触发sum侦听器
	sum(x){
		console.log('x',x);
	},
	//使用deep,obj中任意一项修改都会触发侦听器
	obj:{
		handler: function(val){
			console.log('obj',val);
		},
		deep: true
	}
},
methods:{
	changeHandle(){
		this.count = this.inputVal;
		this.obj.a++;
	},
}

注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,

2.2、vue3

计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些"副作用":例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。

在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数

bash 复制代码
//vue3 index.vue
<script setup>
	import {ref, computed, watch } from 'vue';
	const inputVal = ref('');
	/*侦听单个ref*/
	watch(inputVal,(newVal,oldVal)=>{
		console.log('inputVal',newVal);
	})
	
	const x = ref(1);
	const y = ref(2);
	const sum = ref();
	
	/*getter函数侦听*/
	watch(()=> x.value*1 + y.value*1,(val)=>{
		//x,y任意一个变量发生变化,都会被侦听
		console.log('val',val);
		sum.value = val;
	})
	
	//多个来源组成的数组
	watch([x,()=> y.value],(newVal,oldVal)=>{
		console.log('新值',newVal);//[]数组格式,第一个值对应x,第二个值对应y
		console.log('旧值',oldVal);
	})
	watch([x,y],([newX,newY],[oldX, oldY])=>{
		console.log('新x:',newX);
		console.log('新y:',newY);
		console.log('旧x:',oldX);
		console.log('旧y:',oldY);
	})
	function submitHandle(){
		// firstName.value = '李';
		firstName.value = inputVal.value;
		// x.value++;
		y.value++
	}
</script>

<template>
<div class="index-main">
	<input v-model="inputVal" placeholder="请输入新的姓" />
	<div>x:{{x}}</div>
	<div>y:{{y}}</div>
	<div>sum:{{sum}}</div>
	<input v-model="x" placeholder="请输入内容" />
	<button @click="submitHandle">修改</button>
</div>
</template>

ES6箭头函数

const x = ()=> x.value1 + y.value 1

等价于ES5函数表达式

const x = function(){

return x.value1 + y.value 1

}

响应式对象的监听

bash 复制代码
//错误写法
const obj = reactive({num:0});
watch( obj.num,(numVal)=>{
	console.log('num:',numVal);
})
bash 复制代码
//正确写法
const obj = reactive({num:0});
watch( ()=> obj.num,(numVal)=>{
	console.log('num:',numVal);
})

深层侦听器

当直接传入一个响应式对象,会隐式的创建一个深层侦听器;

例如下面第二个watch的写法,直接侦听obj;

bash 复制代码
//vue3 index.vue
<script setup>
	import {ref, reactive, watch } from 'vue';
	
	const obj = reactive({num:0,age:18});
	/*只能监听obj.num,age变化时不会触发*/
	watch( () => obj.num,(numVal)=>{
		console.log('num:',numVal);
	})
	
	watch(obj,(newObj,oldObj)=>{
		console.log('obj',newObj,oldObj);
	})
	function submitHandle(){
		// obj.num++;
		obj.age++
	}
</script>

<template>
<div class="index-main">
	<button @click="submitHandle">修改</button>
</div>
</template>

深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。

即时回调侦听器

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。

我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行

bash 复制代码
/*首次加载时sum值为空,只有触发一次submitHandle方法修改x或者y值时sum才会有值*/
watch(()=> x.value*1 + y.value*1,(val)=>{
	//x,y任意一个变量发生变化,都会被侦听
	console.log('val',val);
	sum.value = val;
})

/*传入 immediate: true 选项来强制侦听器的回调立即执行*/
/* **
watch(()=> x.value*1 + y.value*1,(val)=>{
	console.log('val',val);
	sum.value = val;
},{
	immediate: true
})
** */

一次性侦听器

每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项

bash 复制代码
watch(()=> x.value*1 + y.value*1,(val)=>{
	console.log('val',val);
	sum.value = val;
},{
	once: true
})

watchEffect侦听器的介绍

计算属性 VS 侦听器

以下这种情况,建议使用计算属性,使用侦听器时需监听两个变量;

bash 复制代码
//vue3 index.vue
<script setup>
	import { ref, computed, watch } from 'vue';
	const firstName = ref('张');
	const lastName = ref('三');
	const fullName = ref('张三');
	/*计算属性*/
	const full2 = computed(()=>{
		return firstName.value + ' ' + lastName.value
	})
	/*侦听器*/
	watch(firstName, (newVal)=>{
		fullName.value = newVal + ' ' + lastName.value
	})
	watch(lastName, (newVal)=>{
		fullName.value = firstName.value + ' ' + newVal
	})
	function submit(){
		firstName.value = '李';
	}
	function submit2(){
		lastName.value = '四';
	}
</script>

<template>
	<div class="index-main">
		<div>firstName:{{firstName}}</div>
		<div>lastName:{{lastName}}</div>
		<div>FullName:{{fullName}}</div>
		<div>full2:{{full2}}</div>
		<div>full3:{{full3}}</div>
		<button @click="submit">姓修改</button>
		<button @click="submit2">名修改</button>
	</div>
</template>

计算属性 VS 方法

虽然使用方法可以得到计算属性相同的结果,但是方法无法缓存;

计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。

方法调用总是会在重渲染发生时再次执行函数;

相关推荐
醉の虾9 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧18 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm28 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
chusheng184031 分钟前
Java项目-基于SpringBoot+vue的租房网站设计与实现
java·vue.js·spring boot·租房·租房网站
asleep70140 分钟前
第8章利用CSS制作导航菜单
前端·css
hummhumm44 分钟前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
游走于计算机中摆烂的1 小时前
启动前后端分离项目笔记
java·vue.js·笔记
幼儿园的小霸王1 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒1 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
码蜂窝编程官方2 小时前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游