这一章主要整理一下vue中computed(计算属性)和watch(监听属性)的用法。
1.computed
computed主要的做的是元数据进行加工返回一个新的数据。
案例一、现在data中有firstName 和lastName两个值,显示全名
解决方法一:{{firstName + ' ' + lastName}}
这是最简单的方法,在计算的数据量比较少的时候可以采用。
解决方法二:computed
var vm = new Vue({
el: "#app",
template: `
<div>
<p>name : {{name}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming"
},
computed: {
name() {
return `${this.firstName} ${this.lastName}`;
}
},
})
解决方法三:methods
var vm = new Vue({
el: "#app",
template: `
<div>
<p>name : {{getName()}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming"
},
methods: {
getName() {
return `${this.firstName} ${this.lastName}`;
}
},
})
可以看到其实方案二和方案三都实现的要求,但是推荐使用方案二,原因主要是:computed只有再依赖的数据发生改变的时候才会重新计算(缓存机制),而methods在任意数据改变的时候都会重新去计算。
测试案例:
var vm = new Vue({
el: "#app",
template: `
<div>
<p>name1 : {{name}}</p>
<p>name2 : {{getName()}}</p>
<p>number: <input type="text" v-model='number' /> </p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
number: 0
},
computed: {
name() {
console.log('recalculate computed')
return `${this.firstName} ${this.lastName}`;
}
},
methods: {
getName() {
console.log('recalculate methods')
return `${this.firstName} ${this.lastName}`;
}
},
})
输出结果(当在input框中不断改变number的值)
可以发现,这时候每次number的值改变都会触发methods中的getName()方法。
computed执行setter操作(不推荐,但是有computed有这个功能)
案例二、输入全名,然后依据输入的全名改变data中的firstName和lastName。
var vm = new Vue({
el: "#app",
template: `
<div>
<p>firstName : {{firstName}}</p>
<p>lastName : {{lastName}}</p>
<p>name : <input type="text" v-model='name' /> </p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
number: 0
},
computed: {
name: {
get() {
console.log('recalculate computed')
return `${this.firstName} ${this.lastName}`;
},
set(name) {
const names = name.split(' ');
this.firstName = names[0];
this.lastName = names[1];
}
}
}
})
改变输入框中的name,得到输出结果:
2.watch
watch是监听一个值的变化,然后进行一系列的操作。
案例三、还是上面的例子用watch也能实现(比较麻烦,需要监听firstName和lastName两个值的变化,不推荐,这里只是作为一个例子)。
var vm = new Vue({
el: "#app",
template: `
<div>
<p>firstName : <input type='text' v-model='firstName' /></p>
<p>lastName : <input type='text' v-model='lastName' /> </p>
<p>fullName : {{fullName}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
fullName: ''
},
watch: {
firstName(newValue, oldValue) {
this.fullName = newValue + ' ' + this.lastName;
}
}
})
输出结果:
可以看出刚开始fullName是空的,这是因为第一次刚渲染完成的时候watch默认是不执行的,改变下firstName输出结果:
这样就看到了我们想要的结果,那如果要求第一次渲染的时候就要执行watch,方法如下:
var vm = new Vue({
el: "#app",
template: `
<div>
<p>firstName : <input type='text' v-model='firstName' /></p>
<p>lastName : <input type='text' v-model='lastName' /> </p>
<p>fullName : {{fullName}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
fullName: ''
},
watch: {
firstName: {
handler(newValue, oldValue) {
this.fullName = newValue + ' ' + this.lastName;
},
immediate: true //即时,即立刻执行的意思。
}
}
})
这样我们就可以得到第一次渲染的时候 watach方法也执行了 结果:
和上例中的immediate一样,还有设置deep参数
deep表示监听深度监听
案例四、在data中有一个obj对象,需要监听obj.a的变化
var vm = new Vue({
el: "#app",
template: `
<div>
<p>obj.a : <input type='text' v-model='obj.a' /></p>
<p>obj.b : <input type='text' v-model='obj.b' /></p>
</div>
`,
data: {
obj: {
a: 0,
b: 'a'
}
},
watch: {
obj: {
handler(newValue, oldValue) {
console.log('watch obj.a changed')
},
immediate: false //即时,即立刻执行的意思。
}
}
})
可以看到上例监听了obj的变化,但是obj.a进行改变的时候,输出结果:
说明并没有执行watch下面监听的函数,这时候上deep:true,再次进行测试,输出结果:
但是,我们继续改变obj.b的值,发现监听又再次触发了,其输出结果:
这个说明,一旦加了deep:true的属性之后,vue会遍历监听的obj下面说有值,但其实我们只想要监听obj.a,而且这样效率也低下,再次修改:只需要将监听的obj改成'obj.a'即可
var vm = new Vue({
el: "#app",
template: `
<div>
<p>obj.a : <input type='text' v-model='obj.a' /></p>
<p>obj.b : <input type='text' v-model='obj.b' /></p>
</div>
`,
data: {
obj: {
a: 0,
b: 'a'
}
},
watch: {
'obj.a': {
handler(newValue, oldValue) {
console.log('watch obj.a changed')
},
immediate: false, //即时,即立刻执行的意思。
deep: false
}
}
})
改过之后发现及时deep为false,但是修改obj.a的时候能正常触发监听,改变obj.b的时候无法触发监听。
案例四、当在watch的中改变被监听的值。
可以试想一下,如果监听obj.a,你又在监听触发的方法中改变了obj.a的会造成什么后果。
ok,这想必大家都知道,那就是死循环,所以千万不要用。
var vm = new Vue({
el: "#app",
template: `
<div>
<p>obj.a : <input type='text' v-model='obj.a' /></p>
<p>obj.b : <input type='text' v-model='obj.b' /></p>
</div>
`,
data: {
obj: {
a: 0,
b: 'a'
}
},
watch: {
'obj.a': {
handler(newValue, oldValue) {
this.obj.a += 1;
console.log('watch obj.a changed')
},
immediate: false, //即时,即立刻执行的意思。
deep: false
}
}
})
稍稍改变一下a的值,可以看到结果:
上图结果obj.a的值还为0是因为,浏览器直接卡崩了。好了,所以千万不要在watch监听中去改变本身。