Vue基础篇--计算属性(computed) 和侦听器(watcher)
计算属性
使用示例
计算属性:类似于使用getter函数获得的一个属性值,使用属性访问的方式从一个function中获取属性的结果,并且这个结果可以根据function中响应式数据的变化而自动变化。它的优点有:
- 用一个变量替代去替代一个复杂的表达式
- 可以将表达式的计算结果缓存供下次使用
举个例子说明,data中定义了一个message变量,现在我们需要将这个message中的字符全部颠倒后在页面中展示,可以使用下面的几种方法
<div id="example">
<p> 原 message {{ message }}</p>
<p> 方法一:{{ message.split('').reverse().join('') }} </p>
<p> 方法二:{{ reversedMsg() }} </p>
<p> 方法三:{{ reversedMessage }} </p>
</div>
<script>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
methods:{
reversedMsg(){
return this.message.split('').reverse().join('')
}
}
computed: {
// 计算属性的 getter
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
})
</script>
第三种使用方式为计算属性,它的使用方式和data种定义的message变量的使用方式相同,使用this.reversedMessage便可以访问。它的值会自动根据reversedMessage函数计算得到,且会根据函数内部的响应式数据this.message的改变而自动改变。
比较它与前两种方式的优缺点:
方法1:直接使用模板语法
- 这样的书写方式复杂,不利于阅读理解,代码可读性差
- 如果多个地方都需要展示这个结果,这个表达式要写多遍
- 如果多个地方使用该值,也会执行多遍计算
方法2:使用一个函数返回值表示
- 如果多个地方使用该值,这个函数会执行多遍
方法3:计算属性
- 因为内部有缓存机制,只进行一次计算,后面直接使用上次的结果。
计算属性缓存
计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。所以这个例子中只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
由于属性的更新只和内部响应式依赖相关,所以下面该属性值,无论在哪个时刻调用,结果都是不会改变的。如果希望它改变,使用上面第二种函数的方式
computed: {
now: function () {
return Date.now()
}
}
计算属性的setter
计算属性可以获取值,也可以重新给他赋值,这就需要定义setter函数
data:{
firstName: 'Foo',
lastName: 'Bar',
}
computed: {
fullName: {
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter, 执行this.fullName = "A B"表达式时,set函数触发,newValue形参接受"A B"参数
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[-1]
}
}
}
侦听器watcher
简单来说,可以设置监听一个表达式或函数的结果变化。变化时执行回调函数,回调函数得到的参数为变化前后的新值和旧值,表达式支持单个变量和一个简单的属性访问路径,需要监听更复杂的表达式,需要使用函数取代。
常见的几种用法
var vm = new Vue({
el:"",
methods:{},
data: { msg: "", msg2:""},
watch:{
"msg": function(newVal, oldVal){}, // 当data中msg 发生改变时,触发执行该函数。
"msg2":function(newVal, oldVal){},
"$route.path": function(newVal, oldVal){} // 当路由变量发生改变时候,触发该函数
function(){
return this.msg + this.msg2
}
}
})
// 外部定义
var unwatch = vm.$watch("a.b.c", function(new, old){
// 监听回调
})
// 调用 unwatch() 取消监听
$watch函数会得到一个unwacth函数对象,执行该函数,将会取消这个监听器。
被监听的变量如果是一个引用类型,例如对象或者数组,那个这个引用类型内部的数据更改并不会触发watch 回调,只有监听的对象发生了替换,才会视作一个更改操作,从而触发回调函数。为了可以发现内部值的变化,需要增加一个deep:true的选项,而immediate参数可以阻止该监听器第一次回调时就取消该监听。
var unwatch = vm.$watch("a.b.c", function(new, old){},{’deep‘: true, 'immediate':true})
监听器的回调函数不能使用箭头函数语法定义,因为箭头函数会自动绑定父级的this指针,会造成原本的this指针被覆盖。
监听器和计算属性的选择
使用官网的例子比较两者的使用:功能 展示fullName,且fullName 在firstName和lastName任意一个更新时进行更新
<div id="demo">{{ fullName }}</div>
第一种:使用监听器,监听 firstName 和 lastName,两个变量改变时都触发更新
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
第二种:使用计算属性,fullName会始终依赖于 firstName 和 lastName 进行同步更新
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
总结:
- 在大多数场景下都更加适合使用计算属性解决需求,因为计算属性内部会自动监听依赖的响应式变量,也实现了侦听器的效果,更偏向于可以自动获取某个结果需求。
- 监听器主要用在触发一个异步操作,计算时间过长的操作。更偏向于触发某个操作的考虑而不是获取结果