跳转到主要内容

主页内容

Vue基础(四)计算属性和监听器

由 webadmin 发布于 阅读 46 次

1、计算属性

在插值表达式和指令中,我们可以写表达式。但是无论是指令(v-text/v-html)还是插值表达式设计的初衷都是为了数据渲染或简单的运算。如果在指令或插值表达式中写入太多的逻辑,会造成模板过重和难以维护。这样带来的问题有以下几点:

1、模板中存在大量的运算。

2、代码无法复用。

为了解决这些问题,我们可以使用计算属性computed。计算属性通过计算得到的一个属性,这个属性也会成为data中的属性。如果计算属性是依赖于原data中的值,那么当data中的值发生改变时,计算属性随之改变。

1.1、基础例子

例如:要实现拼接两个字符串。

(1)、在插值表达式中实现:

<div id="root">
        <div>
            <p>在模板中通过表达式实现:{{firstName + '' + lastName}}</p>
        </div>
</div> 
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                firstName: '张',
                lastName: '三'
            },
        });
</script>

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。

(2)、使用计算属性实现

<div id="root">
        <div>
            <p>通过计算属性组合的姓名为:{{fullName}}</p>
        </div>
</div> 
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                firstName: '张',
                lastName: '三'
            },
            //computed是计算属性配置项
            computed: {
                // 在计算属性中定义的是函数,在函数中处理逻辑,
                // 并把计算出来的值return出去,函数名就是计算属性的名称
                fullName(){
                    return this.firstName + " " + this.lastName;
                }
            }
        });
</script>

(3)、使用方法实现

<div id="root">
        <div>
            <p>通过调用方法实现姓名为:{{ fullNameFn() }}</p>
        </div>
    </div> 

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                firstName: '张',
                lastName: '三'
            },
            methods:{
                fullNameFn(){
                    return this.firstName + " " + this.lastName;
                }
            }
        });
    </script>

示例运行结果:

1.2、计算属性缓存VS方法

通过以上实例可以看出,使用方法和使用计算属性能实现同样的效果。我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只有在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 firstNamelastName 还没有发生改变,多次访问 fullName计算属性会立即返回之前的计算结果,而不必每次都执行一遍函数。

这也同样意味着下面的计算属性将不再更新,因为 Date.now()不是响应式依赖:

<div id="root">
        <div>
            <p>现在的时间是:{{dateNow}}</p>
        </div>
    </div> 

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{},
            //computed是计算属性配置项
            computed: {
                // 在计算属性中定义的是函数,在函数中处理逻辑,
                // 并把计算出来的值return出去,函数名就是计算属性的名称
                dateNow(){
                    return Date.now();
                }
            }
        });
    </script>

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行Agetter。但是,有的场景下,如果不希望有缓存,可以用方法来替代。

1.3、计算属性的setter

计算属性默认只有getter,不过在需要时你也可以提供一个setter

以上的例子中定义的计算属性都只有getter,例如:

fullName(){
   return this.firstName + " " + this.lastName;
}

如果需要setter,可以使用如下定义方式:

fullName:{
   get(){
       return this.firstName + " " + this.lastName;
   },
   set(newValue){
       this.firstName = newValue.substr(0, 1);
       this.lastName = newValue.substr(1);
   }
}

现在再控制台运行:vm.fullName ="张无忌"setter 会被调用,vm.firstNamevm.lastName 也会相应地被更新。

计算属性使用起来不难,但是难点在于你不知道什么时候要使用计算属性:当我们需要的一个值是经过data里的数据计算得到的时候(依赖于data里面的数据),就要使用计算属性,好处是:计算属性关联的数据发生改变了,计算属性也会跟着改变;计算属性有缓存,能提高效率;

2、侦听器

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。当挂载点内部的绑定数据发生变化,如果我们需要执行一些处理程序或处理业务逻辑,就可以使用Vue的侦听器watch属性。

侦听器是用来侦听data数据是否发生变化的。一旦data数据发生改变,就会执行某个行为。

示例代码:实现监听姓名被修改的次数。

<div id="root">
        <div>
            <!-- 
                无论是firstName还是lastName发生改变都算是一次姓名发生改变
             -->
            姓氏:<input type="text" v-model="firstName"><br />
            名字:<input type="text" v-model="lastName">
            <p>通过计算属性组合的姓名为:{{fullName}}</p>
            <p>姓名发生了改变:{{count}}次</p>
        </div>
</div> 

<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data:{
                firstName: '张',
                lastName: '三',
                count: 0
            },
            computed:{
                fullName(){
                    return this.firstName + ' ' + this.lastName;
                }
            },
            //watch:侦听器,用来侦听data数据是否发生变化的。一旦data数据发生改变,就会执行某个行为
            //watch里面定义的是函数,函数名就是我们要监听的data中的变量名
            watch:{
                firstName(){
                    this.count++;
                },
                lastName(){
                    this.count++;
                }
            }
            
        });
</script>

运行结果:

侦听器watch中定义的是函数,函数名就是我们要监听的data中的变量名。比如上面的示例中,我们要监听的data中的属性是firstNamelastName,所以在watch配置项中定义了函数就是:

watch:{
    firstName(){
       //具体业务逻辑
    },
    lastName(){
       //具体业务逻辑
    }
}