对于初学者来说,学到计算属性和监听(侦听)属性这里很容易犯晕,搞不懂这两者之前的区别和什么时候该使用哪个,这里Dapan就来尝试梳理一下计算属性(computed)和监视(侦听)属性(watch)的区别,以及该选择使用哪一个:
1. 能用computed实现的尽量用computed实现:
假如现在我们要实现一个自动组成人的全名(fullName)的小案例,如下:
看看用watch和computed分别如何实现该功能:
用watch实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>watch和computed(watch实现)</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="root">
firstName:<input type="text" v-model="firstName" /><br />
lastName:<input type="text" v-model="lastName" /><br />
fullName:
<h3>{{fullName}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
fullName: '',
},
watch: {
firstName(newValue) {
this.fullName = newValue + '-' + this.lastName;
},
lastName(newValue) {
this.fullName = this.firstName + '-' + newValue;
},
},
});
</script>
</body>
</html>
用watch实现的代码时命令式的,且是重复的。什么是命令式的呢?简单来说就是这里要Vue亲自监视firstName和lastName的变化。
补充:命令式编程:命令“机器”如何去做事情 (how),这样不管你想要的是什么 (what),它都会按照你的命令实现。
用computed实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>watch和computed(computed实现)</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="root">
firstName:<input type="text" v-model="firstName" /><br />
lastName:<input type="text" v-model="lastName" /><br />
fullName:
<h3>{{fullName}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed: {
fullName() {
return this.firstName + '-' + this.lastName;
},
},
});
</script>
</body>
</html>
显而易见, 用computed实现是声明式的,且比用watch实现会更简单易于理解一点。
补充:声明式编程:告诉“机器”你想要的是什么 (what),让机器想出如何去做 (how)。
假如现在在实现刚刚那个功能的基础上再加一个功能,在firstName修改两秒钟之后,fullName再修改:
看看watch怎么实现该功能:
watch: {
firstName(newValue) {
// setTimeout:
setTimeout(() => {
this.fullName = newValue + '-' + this.lastName;
}, 2000);
},
lastName(newValue) {
this.fullName = this.firstName + '-' + newValue;
},
},
用了一个很简单的setTimeout
就实现了,再来看看computed能不能实现:
computed: {
fullName() {
setTimeout(()=>{
return this.firstName + '-' + this.lastName;
},2000)
},
},
打开live Server发现并没有实现该功能,是因为computed不支持异步操作(这里的返回值交给的是setTimeout
,计算属性computed并没有拿到返回值,此时computed的返回值是undefined,计算属性是靠返回值拿数据,而我们办不到让计算属性等一等再有返回值,故计算属性不能开启异步任务去维护数据。),而watch支持异步,因为watch不是靠返回值,而是靠你亲自写的代码去修改。
小结:当需要在数据变化时执行异步或开销较大的操作时使用watch,但计算属性在大多数情况下更合适。
computed的缓存机制:
<div id="root">
姓:<input type="text" v-model="firstName" /><br />
名:<input type="text" v-model="lastName" /><br />
姓名:
<h3>{{fullName}}</h3><br>
姓名:
<h3>{{fullName}}</h3><br>
姓名:
<h3>{{fullName}}</h3><br>
姓名:
<h3>{{fullName}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed: {
fullName() {
return this.firstName + '-' + this.lastName;
},
},
});
</script>
这里在页面上显示了四次fullName,但是由于computed的缓存机制,计算属性只被调用了一次,其他三次的fullName是上次缓存下来的值,也就是说计算属性会直接从缓存拿值,只有当计算属性所依赖的数据发生改变时才会重新执行计算属性:
而watch并没有缓存机制。
计算属性是代码刚开始还没有有数据改变的时候就执行一次,而watch是当监视的属性发生变化时才会执行,除非配置immediate:true
:
<div id="root">
firstName:<input type="text" v-model="firstName" /><br />
lastName:<input type="text" v-model="lastName" /><br />
fullName:
<h3>{{fullName}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
fullName: '',
},
watch: {
firstName(newValue) {
this.fullName = newValue + '-' + this.lastName;
},
lastName(newValue) {
this.fullName = this.firstName + '-' + newValue;
},
},
});
</script>
打开live Server,fullName并没有立即显示在页面上:
<div id="root">
姓:<input type="text" v-model="firstName" /><br />
名:<input type="text" v-model="lastName" /><br />
姓名:<h3>{{fullName}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed: {
fullName() {
return this.firstName + '-' + this.lastName;
},
},
});
</script>
fullName已经显示在了页面上:
但是当我在watch上加了immediate:true
之后:
<div id="root">
firstName:<input type="text" v-model="firstName" /><br />
lastName:<input type="text" v-model="lastName" /><br />
fullName:
<h3>{{fullName}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
fullName: '',
},
watch: {
firstName: {
immediate: true, //watch会立即执行
handler(newValue) {
this.fullName = newValue + '-' + this.lastName;
},
},
lastName: {
immediate: true, //watch会立即执行
handler(newValue) {
this.fullName = this.firstName + '-' + newValue;
},
},
},
});
</script>
watch会立即执行:
watch监听的必须是data中已经存在的数据,而computed是计算得出来的数据,并且挂载到了vm身上。
计算属性必须有return,而监听属性没有return
watch可以拿到新旧数据,而computed拿不到旧数据
watch:{
监听的属性名(newValue,oldValue){
console.log(newValue,oldValue)
}
}
fullName(){retrun this.filstName + this.lastName}
的就是将return的值赋值给fullName,并将这个fullName挂载到vm上,作为vm的一个属性(类似于data中的属性)。而监听属性是监听data中某一属性发生改变时,要进行的一些列操作。
以上知识只是Dapan的个人总结,有什么错误的地方欢迎大家批评指正。转载的话请在后台告知Dapan哦,谢谢!
关注公众号: 学编程的GISer,大家一起学习进步!