VueJS Computed 属性
-
为什么要计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:<div id="example"> {{ message.split('').reverse().join('') }} </div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。所以,对于任何复杂逻辑,你都应当使用计算属性。
-
示例
下面的示例演示了如何在 vue 中使用计算属性:
尝试一下<div id="example"> <p>原始消息: "{{ message }}"</p> <p>计算后的反向消息: "{{ reversedMessage }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 计算属性的 getter reversedMessage: function () { // `this` 指向 vm 实例 return this.message.split('').reverse().join('') } } }) </script>
示例说明:输出的结果是原始消息: "Hello" 计算后的反向消息: "olleH"
这里我们声明了一个计算属性 reversedMessage。我们提供的函数将用作属性 vm.reversedMessage 的 getter 函数:console.log(vm.reversedMessage) // => 'olleH' vm.message = 'Goodbye' console.log(vm.reversedMessage) // => 'eybdooG'
你可以打开浏览器的控制台,自行修改例子中的 vm。vm.reversedMessage 的值始终取决于 vm.message 的值。你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。
-
计算属性的缓存效果
你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:
尝试一下<div id="example"> <p>在methods方法中定义也能输出倒转的消息: "{{ reversedMessage() }}"</p> </div> // 在组件中 <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script>
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:computed: { now: function () { return Date.now() } }
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
-
计算属性中的 Get/Set 函数
我们将使用一个示例来了解计算属性中的 Get/Set 函数。
尝试一下<div id = "computed_props"> <input type = "text" v-model = "fullname" /> <h1>{{firstName}}</h1> <h1>{{lastName}}</h1> </div> <script> var vm = new Vue({ el: '#computed_props', data: { firstName : "Terry", lastName : "Ben" }, methods: { }, computed :{ fullname : { get : function() { return this.firstName+" "+this.lastName; } } } }); </script>
我们定义了一个绑定到全名的输入框,全名是计算属性。 它返回一个名为get的函数,该函数给出全名,即名字和姓氏。 此外,我们将名字和姓氏显示:<h1>{{firstName}}</h1> <h1>{{lastName}}</h1>
让我们在浏览器中检查一下输出结果如下图:现在,如果我们在文本框中更改名称,我们将看到以下屏幕快照中显示的名称中没有反映出相同的名称。让我们在全名计算属性中添加 set 函数看看:
尝试一下<div id = "computed_props"> <input type = "text" v-model = "fullname" /> <h1>{{firstName}}</h1> <h1>{{lastName}}</h1> </div> <script> var vm = new Vue({ el: '#computed_props', data: { firstName : "Terry", lastName : "Ben" }, methods: { }, computed :{ fullname : { get : function() { return this.firstName+" "+this.lastName; }, set : function(name) { var fname = name.split(" "); this.firstName = fname[0]; this.lastName = fname[1] } } } }); </script>
它具有名称作为参数,除了文本框中的全名外,什么都没有。 以后,它在空间上分割,并且姓和名被更新。 现在,当我们运行代码并编辑文本框时,相同的内容将显示在浏览器中。 由于设置了功能,名字和姓氏将被更新。 如果编辑了任何内容,get 函数将返回名字和姓氏,而 set 函数将对其进行更新。如下图修改文本框值输出的结果:现在,你可以在上面示例点击尝试一下体验一下文本框中键入的内容与上面的屏幕快照中显示的内容匹配。