继续上一篇的内容:
计算属性的缓存特征 vs 定义方法(Methods)
也许你已经注意到我们完全可以通过在模板表达式中调用一个方法来实现相同的效果,如下所示
<p>Reversed message: "{{ reverseMessage() }}"</p>
// in component
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('')
}
}
这里我们定义了一个方法来代替计算属性,也实现了与计算属性相同的功能。 从最终结果来看,这两种方式几乎完全一样。然而即使是双胞胎,他们终究是两个独立的个体,要不也不用浪费心思一下创造俩了。有个重要的区别的是计算属性是有依赖项目的,通过其它依赖项来得出的一个我们需要的结果,也正因为此,在Vue里它有个待遇那就是缓存。只要没有依赖项发生变化,它就可以偷懒不重新计算,而把缓存结果直接返回就好。对应到上一个例子中:只要message没发生变化,计算属性会立即返回上一次计算的结果。换个角度,这也带来了更好的性能(当遇到需要很耗时的计算操作时)。
举个例子验证一下:
computed: {
now: function () {
return Date.now()
}
}
这里Date.now()没有任何响应式的依赖,所以你总会获取到最早一次执行的结果。
相比之下,methods就没这个待遇了,需要很勤快的每次都计算一次(不过当你不需要缓存时你还是需要用到它)。
计算属性 vs Watchers($watch)
😅又是vs,在Vue中还提供了一个更通用的方式去观察和响应vue实例上的数据变化,这便是$watch。当一些数据需要根据其它数据变化时,$wacth是一个很诱人的选择,特别是你就来至AngularJS。不过通常更好的方式是使用计算属性,而不是使用一个命令式的回调。 可以想像下面这种情况:
<div id="demo">{{ fullName }}</div>
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,所以需要同时观察它们两个😇,想想watch都累)。
跟计算属性对比:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
一看computed就高效多了,一下管俩,fullName放在此处也很直观,而且在需要使用fullName的时候和访问data中的属性是一样的this.fullName。
计算 setter
计算属性默认只是 getter,不过在你需要时也可以提供一个 setter:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
现在当你调用 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会被相应更新。
Watchers
虽然比输了 我们还是需要了解下它,在一些场景中一个定制的$watch会显得非常必要。这也是为什么Vue中额外提供一个watch候选方案来观察和响应vue实例上的数据变化的原因。
当你需要想执行一个异步的或者很耗时的操作来响应不断变化的数据,它会变得特别有用。
例如:
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- Since there is already a rich ecosystem of ajax libraries -->
<!-- and collections of general-purpose utility methods, Vue core -->
<!-- is able to remain small by not reinventing them. This also -->
<!-- gives you the freedom to just use what you're familiar with. -->
<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://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: {
// whenever question changes, this function will run
question: function (newQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
methods: {
// _.debounce is a function provided by lodash to limit how
// often a particularly expensive operation can be run.
// In this case, we want to limit how often we access
// yesno.wtf/api, waiting until the user has completely
// finished typing before making the ajax request. To learn
// more about the _.debounce function (and its cousin
// _.throttle), visit: https://lodash.com/docs#debounce
getAnswer: _.debounce(
function () {
var vm = this
if (this.question.indexOf('?') === -1) {
vm.answer = 'Questions usually contain a question mark. ;-)' // 这里是问号
return
}
vm.answer = 'Thinking...'
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
})
},
// This is the number of milliseconds we wait for the
// user to stop typing.
500
)
}
})
</script>
换成markdown后暂时没法直接放例子了 ¬_¬在线DEMO
在上面这个例子中,watch允许我们执行一个异步的操作(访问这个有趣的api),限制了我们操作的频率并且能够在API返回一个最终答案时立即反馈结果。这两件事计算属性都是无法完成的。
😄End,想要了解更多其它设置选项,你可以查看vm.$watch API.