vue入门:(计算属性和侦听器)

  • methods
  • watch
  • computed

 一、methods-方法

在数据渲染是需要基于多个数据时第一种方法,可以采用methods属性中的方法计算返回值来实现,先来看示例:

 1 <div id="example">{{describe()}}</div>
 2 <script>
 3     var vm = new Vue({
 4         el:"#example",
 5         data:{
 6             name:'他乡踏雪',
 7             looks:'beautiful',
 8             // describe:'他乡踏雪:beautiful' -- 注意data中的命名不能与methods中的命名一致,会发生冲突
 9             // 渲染数据时会先取data中的值,即便在表达式中写入的是方法执行也会取data中的数据(采用正则匹配)相当于字符串做方法执行:报错
10         },
11         methods:{
12             describe(){
13                 return this.name + this.looks;
14             }
15         }
16     });
17 </script>

methods并且可以实现当数据发生变化时,或者在相关表达式被被执行时(比如示例中),methods就会触发执行, 但是methods还有一种情况就暴露了他的缺点,来看下面的示例:

 <div id="example">{{describe()}}{{age}}</div>

如果结构是这样的情况,methods中的describe在age发生变化时是不应该执行的,但是他却会执行,所以methods的执行不只是在数据变化和表达式执行时,而且还会在DOM内部分结构重新渲染时也会触发执行。这种情况就产生了额外的计算,影响性能。

 二、watch-侦听器

 基于对methods渲染触发问题的思考,vue还提供了一个侦听器来实现只有相关数据发生变化时才触发执行的watch,来看示例:

 1 <div id="example">{{describe}}{{age}}</div>
 2 <script>
 3     var vm = new Vue({
 4         el:"#example",
 5         data:{
 6             name:'他乡踏雪',
 7             looks:'beautiful',
 8             describe:"他乡踏雪 beautiful",
 9             age:18
10         },
11         watch:{
12             name(){
13                 this.bescribe = this.name + " " + this.looks
14             },
15             looks(){
16                 this.bescribe = this.name + " " + this.looks
17             }
18         }
19     });

侦听器watch就是在watch属性中定义与data中数据同名的方法,当data中的某个数据发生变化时,watch中对应的侦听方法就会触发执行。所以使用watch的侦听机制就不会发生像methods那样非相关数据触发的渲染也会导致方法执行,所以从这个角度来看,watch比methods的性能要好些。

 三、computed-计算属性

watch和methods都存在一个类似的问题,就是代码冗余,vue还提供了一个解决方案,就是计算属性computed,看看通过计算属性computed改良上面的示例代码:

 1 <div id="example">{{describe}}{{age}}</div>
 2 <script>
 3     var vm = new Vue({
 4         el:"#example",
 5         data:{
 6             name:'他乡踏雪',
 7             looks:'beautiful',
 8             age:18
 9         },
10         computed:{
11             describe(){
12                 return this.name + " " + this.looks;
13             }
14         }
15     });
16 </script>

使用计算属性可以直接将属性名用于结构表达式中渲染数据,免去了data中的重复定义数据,并且也只有在相关的数据发生变化时才会被触发,免去了watch中多个数据情况下重复监听。

计算属性computed的功能不只是用来实现计算数据渲染,还可以实现data数据的写入,其实上面的示例只是vue实例的getter方法,所以上面的示例代码可以改写成下面这样:

 1 <div id="example">{{describe}}{{age}}</div>
 2 <script>
 3     var vm = new Vue({
 4         el:"#example",
 5         data:{
 6             name:'他乡踏雪',
 7             looks:'beautiful',
 8             age:18
 9         },
10         computed:{
11             describe:{
12                 get(){
13                     return this.name + " " + this.looks;
14                 }
15             }
16         }
17     });
18 </script>

再来看看setter方法,所谓计算属性的setter方法就是当设置describe的值时,name和looks的值也会发生变化,具体来看示例代码:

 1 <div id="example">{{describe}}{{age}}</div>
 2 <script>
 3     var vm = new Vue({
 4         el:"#example",
 5         data:{
 6             name:'他乡踏雪',
 7             looks:'beautiful',
 8             age:18
 9         },
10         computed:{
11             describe:{
12                 get(){
13                     return this.name + " " + this.looks;
14                 },
15                 set(newVal){
16                     const names = newVal.split(' ');
17                     this.name = names[0];
18                     this.looks = names[1];
19                 }
20             }
21         }
22    });
23 </script>

也就是说计算属性是可读可写的,还有就是computed有一个非常重要的特性就是当数据不发生变化时不会执行getter方法,这对于性能优化有很大的帮助,比如computed中的一个属性依赖多个数据渲染,但是在很多时候只会有部分数据发生变化,这时候是需要对发生变化的数据执行getter方法读取新的数据来实现渲染,其他的数据直接去缓存数据。

但是这也有一个闭端,就是有时候依赖的数据并非观察数据(非vue实例上的数据),但又要时时更新,比如下面这个示例:

1 get(){
2     return this.name + " " + this.looks + ' ' + Date.now();
3 }

当name和looks发生变化时,Date.now()始终渲染的是初始数据,不会更新,针对这种情况,vue在计算属性对象中指定了cache字段来控制是否开启缓存,cache的值为false时关闭缓存,会对每个依赖数据执行getter方法,cache默认为true表示读取缓存。所以上面的代码可以修正为:

1 //关闭缓存
2 cache:false,
3 get(){
4     return this.name + " " + this.looks + ' ' + Date.now();
5 }

到了这里你是不是感觉computed有点过分完美,其实不然,计算属性也是存在缺陷的,比如计算属性的节点被移除,并且模板中其他地方没有在引用该属性的时候,那么这个getter方法就不会执行,比如下面这个示例:(来源vue.js权威指南55页)

 1 <div id="example">
 2     <button @click = 'toggleShow'>Toggle Show Total Price</button>
 3     <p v-if = "showTotal">Total Price = {{totalPrice}}</p>
 4 </div>
 5 <script>
 6     var vm = new Vue({
 7         el:"#example",
 8         data:{
 9             showTotal:true,
10             basePrice:100,
11             sum:0
12         },
13         computed:{
14             totalPrice(){
15                 console.log(this.sum++);
16                 return  this.basePrice;
17             }
18         },
19         methods:{
20             toggleShow(){
21                 this.basePrice = this.basePrice + 1;
22                 this.showTotal = !this.showTotal;
23             }
24         }
25     });
26 </script>

在实例中,观察控制台的sum输出必须是在p标签显示的时候才会执行,并且sum的累加比basePrice累加要慢一倍。也就是证实了当计算属性computed的节点被移除后,并且模板中没有其他地方在引用的话,getter方法就不会执行。

要想他执行的话可以采用以下方法:

<div id="example">
    <button @click = 'toggleShow'>Toggle Show Total Price</button>
    <p>{{totalPrice}}</p>
    <p v-if = "showTotal">Total Price = {{totalPrice}}</p>
</div>

只能是当计算属性一直出现在模板中,getter方法才会被执行。

 

——————————————————————

这里还有关于methods、watch、computed的适应场景分析待续。。。

 

上一篇:PB数据窗口中各项指标的获取方法


下一篇:CSCI446/946