Vue2里computed的get和set到底怎么用?
不少刚开始学Vue2的朋友,对computed里的get和set总是有点懵——明明平时只用个函数也能实现计算,那set存在的意义是啥?啥场景必须用set?今天咱们从实际开发里的需求出发,把computed的get和set拆得明明白白,以后遇到类似需求再也不慌~
先搞懂computed里的get是干啥的
平时写computed,最常见的写法是这样:
computed: { fullName() { return this.firstName + ' ' + this.lastName } }
这种写法其实是get的简写,Vue会自动把这个函数当成computed属性的getter(获取器),它的核心作用是:基于响应式依赖(比如这里的firstName、lastName),动态计算出一个结果,而且Vue给computed做了缓存优化——只要依赖的响应式数据没变化,每次访问fullName时,不会重复执行计算逻辑,直接拿缓存结果,性能更优。
举个实际场景:做用户信息展示模块,姓和名存在data里的firstName、lastName,页面上要显示“全名”,用computed的get来拼接,既保证了全名和姓/名的联动(姓或名改了,全名自动变),又利用缓存减少不必要的计算,这时候只用get就够,因为只是“读”全名这个计算结果。
set什么时候派上用场?
如果只是“读”计算结果,get足够;但要是遇到“写”的场景——也就是需要主动修改computed属性,进而影响它依赖的响应式数据时,set就必须出场了。
举个例子:还是全名的需求,但这次是用户编辑环节——页面上有个输入框,用户要直接输入全名(张三”),你需要把输入的内容拆成“张”(firstName)和“三”(lastName)存到data里,这时候如果直接给fullName赋值(比如this.fullName = '李四'
),Vue会报错,因为默认computed只有get,是只读的,这时候就得给computed加上set,让它变成“可写”的。
再延伸个场景:后台返回的用户信息里,地址是“省-市-区”拼接好的字符串,但前端表单里省、市、区是三个下拉框,编辑时,需要把拼接的地址拆分成省、市、区三个字段回显;保存时,又要把三个字段拼成地址字符串传给后台,这时候用computed的address,get负责拼接显示,set负责拆分赋值,就能优雅解决联动问题。
get和set一起用的完整写法
语法长这样:
computed: { fullName: { // 获取计算结果 get() { return this.firstName + ' ' + this.lastName }, // 当给fullName赋值时触发 set(newVal) { // newVal是赋值时的新值,比如this.fullName = 'Li Si' 时,newVal就是'Li Si' const arr = newVal.split(' ') this.firstName = arr[0] this.lastName = arr[1] || '' } } }
这里要注意两个点:
- get里不需要传参,它自动依赖data里的firstName、lastName,这些数据变了,get会自动重新计算;
- set里接收一个参数newVal,就是给computed属性赋值时的那个“新值”,在set里,你要做的是把这个新值拆解,去修改它依赖的响应式数据(比如firstName、lastName)。
结合实际交互看:页面上有个输入框<input v-model="fullName" />
,用户输入“Wang Wu”后,v-model会触发this.fullName = 'Wang Wu'
,这时set被调用,newVal是'Wang Wu',拆分后给firstName赋值'Wang',lastName赋值'Wu',firstName或lastName变化时,get又会重新计算fullName,输入框内容也会跟着变——这就实现了“输入全名拆分成姓和名,姓或名变化时全名也变”的双向联动。
常见误区:只用get够不够?
很多新手会疑惑:“我不用set,好像也没毛病啊?” 这得看场景:
- 纯展示场景(比如用户信息卡片里的全名):只用get完全够,因为不需要修改computed属性,只需要它跟着依赖变。
- 有交互修改需求(比如编辑时的全名输入框):必须用set!因为如果没写set,直接给computed属性赋值(比如
this.fullName = 'XXX'
),Vue会抛出“Avoid mutating a computed property directly”的错误——意思是“别直接改计算属性啊,它默认是只读的”。
举个反面例子:如果没写set,硬要做编辑场景,你可能得给输入框绑定@input事件,在事件里手动拆分字符串、修改firstName和lastName,但这样代码会很零碎,不如用computed的set把“拆分-赋值”的逻辑封装起来,代码更简洁,也更符合Vue的响应式设计思想。
实战案例:用get和set优化表单处理
假设做一个“用户资料编辑”页面,需求是:
- 姓和名分别存在data的firstName、lastName里;
- 页面上有个“全名”输入框,用户输入全名时,自动拆分到姓和名;
- 姓或名的输入框变化时,全名输入框也自动更新。
不用computed的set的话,代码会很繁琐:
<input v-model="firstName" placeholder="姓" /> <input v-model="lastName" placeholder="名" /> <input v-model="inputFullName" @input="handleFullNameChange" /> <script> export default { data() { return { firstName: '', lastName: '', inputFullName: '' } }, watch: { // 姓或名变化时,更新全名输入框 firstName() { this.inputFullName = this.firstName + ' ' + this.lastName }, lastName() { this.inputFullName = this.firstName + ' ' + this.lastName }, }, methods: { // 全名输入框变化时,拆分到姓和名 handleFullNameChange(e) { const val = e.target.value const arr = val.split(' ') this.firstName = arr[0] this.lastName = arr[1] || '' } } } </script>
但用computed的get和set,代码会简洁很多:
<input v-model="firstName" placeholder="姓" /> <input v-model="lastName" placeholder="名" /> <input v-model="fullName" /> <script> export default { data() { return { firstName: '', lastName: '' } }, computed: { fullName: { get() { return this.firstName + ' ' + this.lastName }, set(newVal) { const arr = newVal.split(' ') this.firstName = arr[0] this.lastName = arr[1] || '' } } } } </script>
可以看到:
- 不用额外的watch和methods,computed的get自动处理“姓/名→全名”的联动;
- set自动处理“全名→姓/名”的拆分赋值;
- 页面上只需要绑定
v-model="fullName"
,逻辑全被computed封装起来了,代码量少了一半还多,维护性也更高。
和methods、watch的区别里,computed的get/set有啥独特性?
最后再对比下,帮大家彻底理清概念:
- 和methods比:methods里的函数每次调用都执行,不管依赖变没变;而computed的get有缓存,依赖不变时直接拿结果,性能更好,而且methods主要是“执行动作”,computed是“计算结果”。
- 和watch比:watch是“监听某个数据变化,执行回调”,属于被动响应;computed的get是“主动根据依赖计算结果”,set是“主动处理赋值时的逻辑”,属于主动管理数据联动,比如watch适合做异步请求、复杂逻辑;computed适合做简单的同步计算+可写控制。
computed的get负责“根据依赖计算结果”,set负责“被赋值时修改依赖”,平时开发里,纯展示用get足够;遇到需要修改computed属性来联动源数据的场景(比如表单编辑、复杂数据拆分/拼接),就得把get和set一起用上,掌握这俩的配合,能让代码更简洁、响应式逻辑更优雅,下次遇到类似需求,别再绕弯路啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。