大家好,我是小杨,一个写了6年前端的老油条。今天想和大家聊聊Vue中一个看似简单但超级实用的功能——计算属性。记得我刚接触Vue时,总觉得data和methods已经够用了,直到发现了计算属性这个"神器",我的代码才真正开始变得优雅起来。
一、计算属性是什么?
简单来说,计算属性就是基于现有数据计算出来的新数据。它就像一个智能的中间人,帮你处理data中的数据,给你想要的结果。
举个🌰,假设我要显示用户的全名:
data() {
return {
firstName: '小',
lastName: '杨'
}
}
没有计算属性时,我可能会这样写:
<p>{{ firstName + ' ' + lastName }}</p>
或者用方法:
methods: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
但有了计算属性,事情就变得简单多了:
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
看起来和方法差不多?别急,它的妙处还在后面呢!
二、计算属性的三大超能力
1. 自动缓存 - 懒人的福音
计算属性最厉害的特点就是缓存。只要依赖的数据不改变,多次访问计算属性会立即返回之前缓存的结果,而不会重新计算。
比如我有一个复杂的计算:
computed: {
complicatedCalculation() {
console.log('重新计算了!')
return this.someData * 100 / Math.PI + 1000
}
}
即使我在模板里用十次:
<p>{{ complicatedCalculation }}</p>
<p>{{ complicatedCalculation }}</p>
<p>{{ complicatedCalculation }}</p>
控制台只会输出一次"重新计算了!"。如果是方法,每次都会重新执行。
2. 响应式依赖追踪 - 智能的管家
计算属性会自动追踪它依赖的响应式数据。只有当依赖变化时,它才会重新计算。
computed: {
userInfo() {
return {
name: this.user.name,
age: this.user.age,
// 只要user.address没被用到,address变化不会触发重新计算
}
}
}
3. 可读可写 - 灵活的双向门
计算属性默认只有getter,但也可以提供setter:
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName
},
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[1] || ''
}
}
}
现在你可以这样用:
// 读取
console.log(this.fullName)
// 设置
this.fullName = '大 杨'
三、什么时候该用计算属性?
根据我的经验,以下场景特别适合使用计算属性:
1. 复杂的数据转换
比如从后端拿到一组数据,需要加工后再显示:
computed: {
filteredProducts() {
return this.products.filter(p => p.price > 100)
.sort((a,b) => b.price - a.price)
.slice(0, 5)
}
}
2. 表单验证
computed: {
emailError() {
if (!this.email) return '邮箱不能为空'
if (!/.+@.+..+/.test(this.email)) return '邮箱格式不正确'
return ''
},
passwordError() {
if (!this.password) return '密码不能为空'
if (this.password.length < 6) return '密码太短'
return ''
},
isValid() {
return !this.emailError && !this.passwordError
}
}
3. 组件props的派生状态
props: ['size'],
computed: {
normalizedSize() {
return this.size.trim().toLowerCase()
}
}
四、计算属性 vs 方法 vs 侦听器
很多新手会困惑:什么时候用计算属性,什么时候用方法,什么时候用watch?
计算属性 vs 方法
-
计算属性:适合需要缓存的结果,基于响应式依赖
-
方法:适合不需要缓存,或者需要参数的情况
// 计算属性 - 无参数,自动缓存
computed: {
currentDate() {
return new Date().toLocaleDateString()
}
}
// 方法 - 可以有参数,每次调用都执行
methods: {
formatDate(date) {
return new Date(date).toLocaleDateString()
}
}
计算属性 vs 侦听器
-
计算属性:声明式的,你告诉Vue你想要什么
-
侦听器:命令式的,你告诉Vue当某些数据变化时要做什么
// 计算属性 - 更简洁
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
// 侦听器 - 更灵活
watch: {
firstName(newVal) {
this.fullName = newVal + ' ' + this.lastName
},
lastName(newVal) {
this.fullName = this.firstName + ' ' + newVal
}
}
五、计算属性的高级用法
1. 结合v-model使用
computed: {
searchQuery: {
get() {
return this.$store.state.searchQuery
},
set(value) {
this.$store.commit('updateSearchQuery', value)
}
}
}
然后在模板中:
<input v-model="searchQuery">
2. 动态计算属性
有时候你可能需要动态创建计算属性:
computed: {
dynamicComputed() {
return () => {
// 根据某些条件返回不同的计算逻辑
if (this.mode === 'simple') {
return this.data.length
} else {
return this.data.reduce((sum, item) => sum + item.value, 0)
}
}
}
}
3. 组合式API中的计算属性
在Vue3的组合式API中,计算属性用起来也很简单:
import { computed } from 'vue'
setup() {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
return {
count,
doubleCount
}
}
六、性能优化小技巧
-
避免在计算属性中做复杂操作:计算属性会在依赖变化时重新计算,复杂的操作会影响性能
-
不要修改依赖数据:计算属性应该是纯函数,不要在里面修改依赖的数据
-
合理拆分计算属性:一个计算属性只做一件事,可以提高可读性和维护性
-
避免长依赖链:计算属性依赖其他计算属性时,链条太长会影响性能
七、常见坑点
-
异步操作:计算属性不能包含异步操作,这时候应该用方法或者watch
-
副作用:计算属性不应该有副作用(如修改DOM、发起请求等)
-
依赖未声明:如果计算属性依赖的数据没有在data中声明,Vue无法追踪变化
// 错误示范
computed: {
badComputed() {
return window.innerWidth // window不是响应式的!
}
}
八、我的实战经验
在做一个电商项目时,我遇到过这样一个需求:需要根据用户选择的筛选条件动态显示商品列表。最初我用watch来实现,代码变得又长又难维护。后来改用计算属性,代码量减少了60%!
重构前:
data() {
return {
products: [],
filteredProducts: [],
category: '',
priceRange: [0, 1000],
sortBy: 'price'
}
},
watch: {
category() {
this.filterProducts()
},
priceRange() {
this.filterProducts()
},
sortBy() {
this.filterProducts()
}
},
methods: {
filterProducts() {
// 一大段过滤和排序逻辑
}
}
重构后:
computed: {
filteredProducts() {
let result = this.products
// 按类别过滤
if (this.category) {
result = result.filter(p => p.category === this.category)
}
// 按价格范围过滤
result = result.filter(p =>
p.price >= this.priceRange[0] &&
p.price <= this.priceRange[1]
)
// 排序
if (this.sortBy === 'price') {
result = [...result].sort((a, b) => a.price - b.price)
} else if (this.sortBy === 'sales') {
result = [...result].sort((a, b) => b.sales - a.sales)
}
return result
}
}
代码不仅更简洁,而且性能也更好,因为计算属性会自动缓存结果,只有依赖变化时才会重新计算。
九、总结
计算属性是Vue中一个非常强大的特性,它能够:
- 让你的代码更简洁、更易读
- 自动缓存计算结果,提高性能
- 智能追踪依赖,只在需要时重新计算
- 可以读写结合,处理复杂逻辑
记住:当你需要基于现有数据派生新数据时,首先考虑计算属性。它能让你的Vue代码从"能用"升级到"优雅"的水平。
我是小杨,一个喜欢分享的前端开发者。如果这篇文章对你有帮助,别忘了点赞收藏。如果有任何问题,欢迎在评论区留言讨论!
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!
