一般来说,既能用computed 实现又可以用 watch 监听来实现的功能,推荐用 computed,重点在于 computed 的缓存功能
computed计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量改变时,计算属性也会跟着改变;它不能计算在data中已经定义过的变量,但是依赖的值必须是data中存在的值。
计算属性与方法的区别:计算属性是基于依赖(依赖就是data中的数据)进行缓存的,只要data中的数据不发生改变,计算属性中的方法是不需要执行的,一直使用缓存中的数据。而方法不依赖data中的数据,也没有缓存,每次调用都重新执行一遍。
- 调用methods中的方法的时候 方法每次会重新调用
- 计算属性方式:当多次调用 reverseString 的时候 只要里面的 num 值不改变,他会把第一次计算的结果直接返回直到data 中的num值改变 计算属性才会重新发生计算 这样如果是比较耗时的功能,没必要每次使用都要重新执行一次,这样会极大地浪费性能
- 函数的调用时需要加()的 计算属性调用不需要加括号
<div id="app">
<!--
当多次调用 reverseString 的时候
只要里面的 num 值不改变 他会把第一次计算的结果直接返回
直到data 中的num值改变 计算属性才会重新发生计算
-->
<div>{{reverseString}}</div>
<div>{{reverseString}}</div>
<!-- 调用methods中的方法的时候 他每次会重新调用 -->
<div>{{reverseMessage()}}</div>
<div>{{reverseMessage()}}</div>
</div>
<script type="text/javascript">
/*
计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存
*/
var vm = new Vue({
el: '#app',
data: {
msg: 'Nihao',
num: 100
},
methods: {
reverseMessage: function(){
console.log('methods')
return this.msg.split('').reverse().join('');
}
},
//computed 属性 定义 和 data 已经 methods 平级
computed: {
// reverseString 这个是我们自己定义的名字
reverseString: function(){
console.log('computed')
var total = 0;
// 只有当data 中的 num 的值改变的时候 reverseString 会自动发生计算。否则就使用第一次计算的结果缓存。
for(var i=0;i<=this.num;i++){
total += i;
}
// 这里一定要有return 否则 调用 reverseString 的 时候无法拿到结果
return total;
}
}
});
</script>
侦听器 watch(数据一旦发生变化就通知侦听器所绑定的方法)。watch 监听的是已经在 data 中定义的变量,当该变量变化时,会触发 watch 中的方法;
根据一个现有数据去生成一个新数据,并且这两个数据会永久的建立关系,还会建立缓存,当无关数据改变的时候,不会重新计算而是直接使用缓存中的值
- 使用watch来响应数据的变化
- 一般用于异步或者开销较大的操作
- watch 中的属性 一定是data 中 已经存在的数据
- 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听
- 侦听器的应用场景:处理异步(ajax,定时任务)或开销较大(耗时)的操作
<div>{{Name}}</div>
data(){
return {
num:0,
lastname:'',
firstname:'',
}
}
//当num的值发生变化时,就会调用num的方法,方法里面的形参对应的是num的新值和旧值
watch:{
num:function(val,oldval){
console.log(val,oldval);
}
},
//计算属性computed,计算的是Name依赖的值,它不能计算在data中已经定义过的变量。
computed:{
Name:function(){
return this.firstname+this.lastname;// 必须有return
}
}
vue使用侦听器来禁止用户不间断重复提交(类似于防抖节流操作) 核心是使用Lodash插件中的方法
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
<style>
/* 这个style必须写在这个文件的上面,否则不起效果 */
[v-cloak] {
/* 元素隐藏 */
display: none;
}
</style>
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p v-cloak>{{ answer }}</p>
</div>
<script src="js/vue.js"></script>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/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, oldQuestion) {
this.answer = "Waiting for you to stop typing...";
this.debouncedGetAnswer();
}
},
created: function() {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500);
},
methods: {
getAnswer: function() {
if (this.question.indexOf("?") === -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),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
除了 watch 选项之外,您还可以使用命令式的 vm.$watch API。