vue爬坑之路4----计算属性
计算属性
-
基础例子
<div id="example">
<p>Original message:"{{ message }}"</p>
<p>Computed reversed message:"{{ reversedMessage}}"</p>
</div>
var vm = new Vue{{
el:'#exammple',
data:{
message:'Hello'
},
computed:{
// a computed getter
reversedMessage:function(){
//'this' points to the vm instance
return this.message.split('').reverse().join('')
}
}
})
结果:
Original message:"Hello"
Computed reversed message:"olleH"
这里我们声明了一个计算属性 reversedMessage 。我们提供的函数将用作属性 vm.reversedMessage 的getter。
console.log(vm.reversedMessage) // ->'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // ->'eybdooG'
打开浏览器的控制台,修改vm。 vm.reservedMessage 的值始终取决于 vm.message的值。
-
计算缓存 vs Methods
通过调用表达式中的method也可以达到同样的效果:
<p>Reversed message:"{{ reverseMessage() }}"</p>
//in comonet
methods:{
reverseeMessage:function(){
return.message.split('').reverse().join('')
}
}
不经过计算属性,我们可以再method中定义一个相同的函数来代替它。两种方式最终的结果是相同的。但是,不同点在于计算属性是基于它的依赖缓存。计算属性只有在它的相关依赖发生改变时才会重新取值。这就意味着只要message没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,不必再次执行函数。
这意味着下面的计算属性将不会更新,因为 Data.now() 不是响应式依赖:
computed:{
now: function (){
return Data.now()
}
}
Data.now() : 返回当前时间字符串
相比而言,每当重新渲染的时候,method调用总会执行函数。
关于缓存。假设有一个重要的计算属性A,这个计算属性需要一个巨大的数组遍历和大量的计算。然后还可能会有其他的计算属性依赖于A。如果没有缓存,我们将重复多次执行A的getter。如果不希望有缓存,用method代替。
-
计算属性 vs Watched Property
Vue.js提供了一个方法 $watch,用于观察Vue实例上的数据变动。当一些数据需要根据其他数据变化时,$watch可以胜任。不过,通常更好的办法是用用计算属性而不是一个命令式的$watch回调。思考下面的例子:
<div id='demo'>{{ fullName }}</div>
var vm = new Vue{(
el:'#domo',
data: {
firstName:'Foo',
lastName:'Bar',
fullNae:'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' '+this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' +val
}
}
})
上面的代码时命令时的和重复的。与计算属性相比:
var vm = new Vue({
el:'#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' +this.lastName
}
}
})
这样更好。
-
计算 setter
计算属性默认只有geter,不过在需要时我们也可以增加一个setter:
//...
computed:{
fullName: {
//getter
get: function (){
return this.firstName +' '+ this.lastName
},
set: function (newValue){
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1 ]
}
}
}
//...
现在在运行 vm.fullName = 'John Doe'时,setter会被调用,John Doe会被存入setter,vm.firstName和vm.lastName也会被对应更新。
观察 watchers
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的watcher。这是为什么Vue提供一个通用的方法通过watch选项,来响应数据的变化。当你想要在数据变化响应时,执行一步操作或开销较大的操作,这是很有用的。
例如:
<div id='watch-example'>
<p>
Ask a yes/no question:
<input v-model='question'>
</p>
<p>{{ answer }}</p>
</div>
<script src='https://unpkg.com/axios@0.12.0/dist/axios.min.js></script>
<script src='http://unpkg.com/lodash@4.13.1/lodash.min.js'></script>
<script>
var watchExampleVM = new Vue({
el:'#watch-example',
data: {
question: ' ',
answer: 'I cannot give you an answer until you ask a question'
},
watch: {
//如果question发生改变,这个函数就会运行
question: function (newQuestion){
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
method:{
//.debounce 是一个通过lodash限制频率的函数。
//在这个例子中,我们希望限制访问yesno.wtf/api的频率
//ajax请求知道用户输入完毕才会发出
getAnswer:_.debounce(
function () {
if(this.questuon.indeOf('?') === -1){
this.answer = 'Questions usually contain a question mark.;-)'
return
}
this.answer='Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response){
vm.answer=_.capitalize(response.data.answer)
})
.catch(function (error){
vm.answer = 'Error! Could not reach the API.'+error
})
},
这是我们为用户停止输入等待的毫秒数
)
}
})
</script>
在这个实例中,使用watch选项允许我们执行异步操作(访问一个API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这是计算属性无法做到的。