1、基础例子
有的时候我们需要在模板中使用数据a,这个时候就需要用到表达式,但是有的地方我们需要对a数据进行一些简单的处理后才能使用,那么我们就会在表达式中写一些js逻辑运算。
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
这样我们的维护就会非常困难,也不便于阅读
2、计算缓存 vs methods
我们就可以在methods里设置一个方法,在模板的表达式中使用这个方法
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
但是这个时候,只要vm中有数据变化,这个变化的数据可能和我们关注的数据无关,但是vm都会重新渲染模板,这个时候表达式中的方法就会重新执行,大大的影响性能。
3、data vs computed vs watch
这个时候其实我们可以使用监听器里完成:
在vm实例中设置watch属性,在里面通过键值对来设置一些监听,键名为数据名,值可以是一个函数,这个函数在数据改变之后才会执行,两个参数分别是更改前的值和更改后的值。
watch:{
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
}
}
值还可以是一个方法名字,当数据改变的时候这个方法会执行
当数据为object的时候,object的键值对改变不会被监听到(数组的push等方法可以),这个时候需要设置深度监听:
c: {
deep:true,
handler:function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
}
},
举例说明deep:
<p><input type="text" v-model="person.name"></p>
data:{
person:{
name:"zhangsan"
}
},
watch:{
person:{ //监听person的变化。
deep:true, //深度监听 更改了对象的属性的时候,他也可以监听到
handler:function(newVlaue,oldValue){
console.log("监听中....")
}
}
}
监听的handler函数前面的这几种写法都是在数据变化的时候才会执行,初始化的时候不会执行,但是如果设置immediate为true就可以了。
watch:{
num(newValue,oldValue){ //这样去写的话不会主动执行一次,需要更改依赖项的时候,才会执行!
},
num:{
immediate:true, //初始化的时候主动执行一次handler
handler:function(newValue,oldValue){
this.nums = newValue*2
}
}
}
我们在回到上面的问题,用监听器加上immediate属性就可以做到该效果,但是大家可以看到的是逻辑稍稍有点复杂
我们一般都会用到一个叫计算属性的东西来解决:
计算属性就是在实例配置项中通过computed来为vm设置一个新的数据,而这个新数据会拥有一个依赖(一条已经存在的数据),当依赖发生变化的时候,新数据也会发生变化
与方法的方式相比,它性能更高,计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
与watch相比,写起来简单,逻辑性更清晰,watch一般多用于,根据数据的变化而执行某些动作,而至于这些动作是在干什么其实无所谓,而计算属性更有针对性,根据数据变化而更改另一个数据
计算属性也拥有getter和setter,默认写的是getter,设置setter可以当此计算属性数据更改的时候去做其他的一些事情,相当于watch这个计算属性
xm:{
get:function(){//getter 当依赖改变后设置值的时候
return this.xing+'丶'+this.ming
},
set:function(val){//setter 当自身改变后执行
this.xing = val.split('丶')[0]
this.ming = val.split('丶')[1]
}
}
注意事项:
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。