什么是computed属性
computed
属性用于声明计算属性,这些属性的值是基于其他响应式属性计算而来的,当依赖的响应式属性发生变化时,计算属性会自动重新计算。
与Vue.js 2相比,Vue.js 3的 computed
属性语法稍有变化,不再使用对象字面量,而是使用类似函数的形式来声明计算属性。此外,Vue.js 3还引入了一个新的 ref
函数,用于创建响应式引用,可以在 setup
函数中使用。
下面是一个简单的Vue.js 3中的 computed
的例子:
<template> <div> <p>{{ message }}</p> <p>{{ reversedMessage }}</p> </div> </template> <script setup> // 使用 <script setup> 语法糖 // 定义响应式数据 const message = ref('Hello, Vue.js 3!'); // 使用 computed const reversedMessage = computed(() => { // 计算属性的值是基于响应式数据 message 计算的 return message.value.split('').reverse().join(''); }); </script>
在上面的例子中,reversedMessage
是一个计算属性,它依赖于 message
反序输出message
的内容
计算属性的作用
computed
属性的存在主要是为了解决一些常见的需求,使得数据的计算和派生更加方便、高效,并确保数据的响应性。
以下是一些使用计算属性的主要原因:
- 「依赖追踪:」 计算属性允许你声明式地描述数据的依赖关系。当依赖的数据发生变化时,计算属性会自动重新计算,而无需手动编写更新逻辑。这有助于避免手动追踪依赖关系,提高代码的可维护性。
- 「缓存:」 计算属性会缓存其结果,只有在依赖发生变化时才重新计算。这意味着如果多次访问同一个计算属性,只有在它的依赖发生变化时才会重新计算,从而提高性能。
- 「简化模板逻辑:」 在模板中,你可以直接使用计算属性,而不必在模板中编写复杂的逻辑或计算。这使得模板更加清晰和易读。
- 「组合逻辑:」 计算属性允许你将一些复杂的逻辑组合成一个属性,使代码更加模块化和可复用。
下面是一个简单的例子,展示了计算属性的用途:
<script setup> import { ref } from 'vue' const radius = ref(5) const area = computed(() => { return Math.PI * radius.value * radius.value }) const circumference = computed(() => { return 2 * Math.PI * radius.value; }) </script>
在上面的例子中,area
和 circumference
都是计算属性,它们依赖于 radius
。当 radius
发生变化时,这两个计算属性会自动更新,而无需手动干预。这样可以使代码更加清晰和易于维护。
computed VS methods
计算属性 (computed
属性) 和普通的函数在Vue.js中的使用有一些区别和优势。计算属性更适合用于模板中的声明式逻辑,特别是涉及到响应式数据的复杂计算。普通函数更适合那些不依赖响应式数据的逻辑或者不需要自动依赖追踪的场景。
区别:
- 「自动依赖追踪:」
- 「计算属性:」 Vue.js 会自动追踪计算属性的依赖关系。只要计算属性中用到的响应式数据发生变化,计算属性就会重新计算。
- 「普通函数:」 普通函数没有自动的依赖追踪。你需要手动管理函数中使用的依赖关系,可能需要使用
watch
来监听变化,或者在模板中使用函数时手动触发更新。
- 「缓存机制:」
- 「计算属性:」 具有缓存机制,只有当依赖变化时才会重新计算。多次访问相同计算属性时,只会计算一次。
- 「普通函数:」 没有内置的缓存机制,每次调用函数都会重新执行。
优势:
- 「简化模板逻辑:」
- 「计算属性:」 用于在模板中声明式地处理复杂的逻辑,使模板更加清晰和简洁。
- 「普通函数:」 在模板中使用普通函数可能导致模板变得复杂,尤其是当逻辑比较复杂时。
- 「性能优化:」
- 「计算属性:」 具有缓存机制,可以避免不必要的重复计算,提高性能。
- 「普通函数:」 没有缓存机制,每次调用都会重新执行,可能导致性能下降。
- 「代码组织:」
- 「计算属性:」 用于将相关逻辑组织成属性,使代码更加模块化和可维护。
- 「普通函数:」 在组件中直接定义函数,可能导致代码分散,难以维护。
可写setter
在Vue.js中,计算属性默认是只读的,也就是说你不能直接在模板中通过v-model或者类似的方式修改计算属性的值。计算属性是依赖于其他响应式数据的,它的值是由这些响应式数据计算而来的。
如果你需要在Vue实例中有一个既能够计算值,又能够被修改的属性,你可以使用 computed
的 get
和 set
方法。这样你就可以通过 v-model
或者手动赋值的方式修改这个属性的值。
以下是一个例子:
<template> <div> <p>Radius: {{ radius }}</p> <p>Area: {{ area }}</p> <input v-model="radius" type="number" placeholder="Enter radius" /> </div> </template> <script setup> import { ref, computed } from 'vue'; const radius = ref(5); const area = computed({ get: () => Math.PI * radius.value * radius.value, set: (newValue) => { // 当修改 area 时,更新 radius radius.value = Math.sqrt(newValue / Math.PI); } }); </script>
在上面的例子中,area
是一个计算属性,通过 get
方法计算值,通过 set
方法监听对 area
的修改,然后反向计算出对应的 radius
。这样你就可以在模板中使用 v-model="area"
来修改 area
的值。
使用getter注意事项
计算属性的 getter
主要用于计算和返回一个派生值,应当保持简单、同步,不应该执行复杂的逻辑或副作用。如果有复杂逻辑或异步操作,应当考虑使用其他适当的方式。当使用计算属性的 getter
时,有一些需要注意的事项:
- 「只返回值:」 计算属性的
getter
应当只返回一个值,而不是执行一些可能产生副作用的操作。计算属性的目的是计算一个值,而不是用于执行命令式的操作。如果你需要执行一些副作用,应该考虑使用生命周期钩子函数或watch
。 - 「不要使用箭头函数:」 在
getter
中,尽量不要使用箭头函数。因为箭头函数没有自己的this
上下文,而在计算属性中,this
指向的是当前 Vue 实例,而非调用它的对象。使用普通函数确保正确的this
上下文。当然在vue3 setup语法糖内是可以使用的箭头函数的。 - 「避免异步操作:」 计算属性的
getter
应当是同步的,不要在getter
中执行异步操作。如果需要异步操作,可以考虑使用watch
或者其他适当的生命周期钩子。 - 「避免修改计算属性依赖的响应式数据:」 计算属性依赖于响应式数据,但在
getter
中应当避免修改这些响应式数据,因为这样会导致无限循环更新。
computed: { myComputedProperty: function() { // 避免在 getter 中修改依赖的响应式数据 // 这样会导致无限循环更新 this.someValue = this.someValue + 1; return this.someValue; } }
小结
- 计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
- 可以使用setter修改计算属性的值
- 不要在 getter 中做异步请求或者更改 DOM