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

1、计算属性computed

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

1.1、vue2计算属性介绍

//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实例修改计算属性时对原值的影响

//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计算属性介绍

//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 来创建:

<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 会随之更新。

//vue3 index.vue
<script setup>
import { ref,computed  } from 'vue';
</script>
<template>
</template>

2、侦听器

2.1、vue2

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

//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的用法

//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 函数在每次响应式状态发生变化时触发回调函数

//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.value1
-
等价于ES5函数表达式
const x = function(){
return x.value1 + y.value1
}

响应式对象的监听

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

深层侦听器

当直接传入一个响应式对象,会隐式的创建一个深层侦听器;
例如下面第二个watch的写法,直接侦听obj;

//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 选项来强制侦听器的回调立即执行

/*首次加载时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 选项

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

watchEffect侦听器的介绍

计算属性 VS 侦听器

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

//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 函数。

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

### Vue.js计算属性侦听器的作用 #### 计算属性的作用 Vue.js 提供了计算属性来处理复杂的逻辑运算,使得模板保持简洁。当依赖的数据发生变化时,计算属性会自动重新求值并更新视图。这种特性非常适合用于基于其他数据派生的状态。 例如,在一个表单验证场景中,如果需要判断输入框的内容是否有效,则可以使用计算属性来进行实时校验: ```javascript // 定义计算属性 computed: { isValid() { return this.inputValue.length >= 6; } } ``` 通过这种方式,`isValid` 属性会在 `inputValue` 变化时自动更新其值[^1]。 #### 侦听器的作用 相比之下,侦听器主要用于观察特定变量的变化,并执行相应的操作或副作用。这适用于那些无法简单地由现有数据推导出来的复杂业务逻辑。比如发送网络请求、修改多个状态等异步任务或者开销较大的同步任务都可以放在侦听函数里完成。 下面是一个简单的例子展示了如何定义一个侦听器: ```javascript // 使用 watch 来监听 inputValue 的变化 watch: { inputValue(newValue, oldValue) { console.log(`Input changed from ${oldValue} to ${newValue}`); } } ``` 每当 `inputValue` 发生改变时,上面这段代码就会触发一次日志记录[^2]。 --- ### 计算属性侦听器之间的主要区别 - **缓存机制**:计算属性具有惰性缓存功能;只有在其所依赖的数据发生变动时才会被重新评估。而侦听器每次检测到目标对象更改都会立即运行回调函数。 - **适用范围**:对于仅需读取某些属性组合后的结果而言,应该优先考虑采用计算属性的方式实现。但如果涉及到更复杂的交互流程或是想要追踪某个具体字段的历史变更情况的话,则更适合选用侦听器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值