Vue&计算属性&计算属性缓存vs方法methods&Vue侦听器

前言:插值表达式的语法相当简洁,使用起来也很方便。但是也不免暴露出它的一些缺点,最典型的就是无法进行复杂逻辑运算。所以,Vue才会自带计算属性的功能。


计算属性

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

1
2
3
4
5
6
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多包含此处的翻转字符串时,就会更加难以处理。

所以,对于任何复杂逻辑,你都应当使用计算属性。

computed

计算属性的本质就是辅助插值表达式来进行复杂逻辑运算的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<p>{{msg}}</p>
<p>{{count}}</p>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
msg: "hello Vue",
},
computed: {
count: function () {
//切割,翻转,拼接
return this.msg.split(" ").reverse().join("===="); //Vue========hello
},
},
});
</script>

上面这个案例就是一个computed的实例演示,我们通过代码不难看出:第一个p标记中的插值表达式显示的是原文,而第二个p标记中,显示的则是经过一系列API处理之后的文本内容。

其中,所有的API操作都放在了computed中的count方法中来实现,而最终插值表达式,只是将computed中处理完毕的属性绑定给自己即可。这也从另一个侧面证实了computed只负责进行复杂逻辑运算的特点。

计算属性setter和getter

  1. 计算属性一般是没有set方法,只读属性
  2. 使用getter方法较多
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <body>
    <div id="app">{{message}}</div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: "#app",
    data: {
    firstName: "kobe",
    lastName: "Bryant",
    },
    // 计算属性一般是没有set方法,只读属性
    computed: {
    // set中方法可以传参数
    // fullName: {
    // set: function () {
    // console.log("----");
    // },
    // },

    fullName: {
    get: function () {
    return this.firstName + " " + this.lastName;
    },
    },
    //与上面方法一样,一般只使用getter方法
    // fullName: {
    // function() {
    // return this.firstName + " " + this.lastName;
    // },
    // },
    },
    methods: {
    full : function () {
    return this.firstName + " " + this.lastName;
    },
    },
    });
    </script>
    </body>

计算属性缓存 vs 方法methods

你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:

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

这也同样意味着下面的计算属性将不再更新,因为computed中的return this.firstName + " " + this.lastName; 不是响应式依赖:

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

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

Vue侦听器

侦听属性,响应数据(data&computed)的变化,当数据变化时,会立刻执行对应函数。

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
<!-- 这里表示被vue控制的区域 -->
<div>{{ fullName }}</div>
{{ age }}
</div>

<script>
const vm = new Vue({
el: "#app", // 控制id为app的元素
data: {
firstName: "li",
lastName: "xinxin",
fullName: "li xinxin",
age: 20,
},
watch: {
firstName() {
console.log("侦听器执行了");
return this.firstName + " " + this.lastName;
},
lastName() {
console.log("侦听器执行了");
return this.firstName + " " + this.lastName;
},
},
});
</script>

如图

侦听器 vs 计算属性

  1. 两者都可以观察和响应Vue实例上的数据的变动。
  2. watch擅长处理的场景是:一个数据影响多个数据。计算属性擅长处理的场景是:多个数据影响一个数据。
  3. 在侦听器中可以执行异步,但是在计算属性中不可以。

当我们可以使用一个功能,使用计算属性、方法、侦听器都可以时,推荐使用计算属性。计算属性的模板较轻,有利于提高浏览器的性能。

参考

Vue官方文档