首页 > 编程笔记
Vue computed(计算属性)详解
当 Vue.js 实例对象的对象属性值发生改变的时候,能自动更新并渲染到 View。但是在实际项目中,Vue.js 实例对象中的数据,会依赖其他数据的改变而改变,View 层需要实时感知到底层数据的变化,从而及时渲染到 View 层并显示。
Vue.js 提供了 computed 和 watch 属性,可以满足这样的项目需求。本节先介绍 computed 的特点、使用方法和注意事项。
以下代码比较难理解和维护:
对于类似这样的复杂逻辑,开发人员应使用 computed 属性实现,代码如下:
因为 reversedMessage 计算属性的值是基于 message 属性计算出来的,所以也可以通过改变 message 属性的值,然后重新计算,得到 reversedMessage 的新值,代码如下:
开发人员可以像绑定普通 property 一样在模板中绑定计算属性。Vue.js 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新,而且最妙的是开发人员已经以声明的方式创建了这种依赖关系:计算属性的 getter() 方法是没有副作用(Side Effect)的,这使它更易于测试和理解。
computed 属性适合于计算时性能开销比较大的数据,这样就避免每次渲染的时候都要重新计算,浪费资源。如果开发人员不希望使用缓存,则可改成使用方法。
Vue.js 提供了 computed 和 watch 属性,可以满足这样的项目需求。本节先介绍 computed 的特点、使用方法和注意事项。
computed计算属性
模板内的表达式在使用时非常便利,但是设计它们的初衷是进行简单运算。在模板中放入太多的逻辑会让模板负担过重且难以维护。以下代码比较难理解和维护:
<div id = "example"> {{ message.split('').reverse().join('')}} </div>在这个地方,模板不再是简单的声明式逻辑。开发人员必须看一段时间才能意识到,这里是想显示变量 message 的翻转字符串。当开发人员在模板中的多处包含此翻转字符串时,就会更加难以处理。
对于类似这样的复杂逻辑,开发人员应使用 computed 属性实现,代码如下:
<div id="app"> <p>基本属性 message: {{ message }}</p> <p>计算属性 reversedMessage: {{ reversedMessage }}</p> </div> <script type="text/javascript"> const vm = new Vue({ el: '#app', data: { message: 'Hello' }, computed: { //计算属性的getter reversedMessage: function() { // 'this' 指向 vm 实例 return this.message.split('').reverse().join(''); } } }); </script>在上面的代码中声明了一个计算属性 reversedMessage,并且定义了一个函数,将这个计算属性赋给这个函数,相当于 vm.reversedMessage 计算属性的 getter() 函数。可以直接通过这个函数获取计算属性 reversedMessage 的值。
因为 reversedMessage 计算属性的值是基于 message 属性计算出来的,所以也可以通过改变 message 属性的值,然后重新计算,得到 reversedMessage 的新值,代码如下:
console.log(vm.reversedMessage); // => 'olleH' vm.message = 'Goodbye'; console.log(vm.reversedMessage); // => 'eybdooG'开发人员可以打开浏览器的控制台,自行修改例子中的 vm。vm.reversedMessage 的值始终取决于 vm.message 的值,如果单独修改 vm.reversedMessage 的值,控制台会提示计算属性不能设置值,因为没有 setter() 方法。需要说明一下,计算属性默认只有 getter() 方法,而没有 setter() 方法,所以这样直接改变计算属性的值会抛出异常,但是计算属性是可以添加 setter() 方法的。
开发人员可以像绑定普通 property 一样在模板中绑定计算属性。Vue.js 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新,而且最妙的是开发人员已经以声明的方式创建了这种依赖关系:计算属性的 getter() 方法是没有副作用(Side Effect)的,这使它更易于测试和理解。
computed属性的setter()方法
computed 属性默认只有 getter() 方法,开发人员是无法直接修改计算属性的值的。如果开发人员需要直接修改计算属性的值,则可以给计算属性添加 setter() 方法。同时定义 fullName 计算属性的 getter() 和 setter()方法,代码如下:<div id="app"> firstName: <input type="text" v-model="firstName"><br/> lastName: <input type="text" v-model="lastName"><br/> fullName: <input type="text" v-model="fullName"><br/> </div> <script type="text/javascript"> const vm = new Vue({ el: '#app', data: { firstName: '', lastName: '' }, computed: { fullName: { get: function() { return this.firstName + ' ' + this.lastName; }, set: function(newValue) { let names = newValue.split(' '); this.firstName = names[0]; this.lastName = names[1]; } } } }); </script>这样就可以在控制台直接给 fullName 计算属性赋予新的值了,如 vm.fullName='zhao liu'。
computed属性同方法的对比
在 Vue.js 中,可以将计算属性绑定到 View 中进行渲染显示,同样可以将一个 Vue.js 实例对象的方法,绑定到 View 中显示方法返回的结果,在页面上都会显示,代码如下:<div id="app"> <div> <p>计算属性:<br/> {{ computedNow }}<br/> </p> <p>方法:<br/> {{ methodNow() }}<br/> </p> </div> </div> <script type="text/javascript"> const vm = new Vue({ el: '#app', methods: { methodNow: function() { console.log("调用了 methodNow 方法"); return Date.now(); } }, computed: { computedNow: function() { console.log("执行了 computedNow 计算属性"); return Date.now(); } } }); </script>但是如果在 View 中同时绑定多次计算属性和方法,则虽然它们的显示效果一样,但是查看控制台时会发现计算属性函数中的打印语句只执行了一次,而函数中的打印语句执行了多次(每绑定一次就执行一次),代码如下:
<div id="app"> <div> <p>计算属性:<br/> {{ computedNow }}<br/> {{ computedNow }}<br/> {{ computedNow }}<br/> </p> <p>方法:<br/> {{ methodNow() }}<br/> {{ methodNow() }}<br/> {{ methodNow() }}<br/> </p> </div> </div> <script type="text/javascript"> const vm = new Vue({ el: '#app', methods: { methodNow: function() { console.log("调用了 methodNow 方法"); return Date.now(); } }, computed: { computedNow: function() { console.log("执行了 computedNow 计算属性"); return Date.now(); } } }); </script>其原因是 computed 属性是基于它们的响应式依赖进行缓存的。也就是说,计算属性会将它们计算的值保存在缓存,只有当它们依赖的响应式数据发生改变后,计算属性才会重新计算,否则就直接从缓存中获取值进行渲染,而方法不一样,每次调用都执行一次。
computed 属性适合于计算时性能开销比较大的数据,这样就避免每次渲染的时候都要重新计算,浪费资源。如果开发人员不希望使用缓存,则可改成使用方法。