计算属性 computed 默认只读,因其本质是基于响应式依赖缓存的 getter 函数;要支持双向绑定,需显式定义 get 和 set 方法,set 中反向更新源数据。

计算属性 computed 默认是只读的,所以直接赋值会报错“Cannot assign to read only property”。这不是 bug,而是 Vue 的设计机制——它要求你显式声明可写的计算属性,才能支持双向绑定(比如用在 v-model 上)。
为什么 computed 默认只读?
Vue 的 computed 本质是基于响应式依赖缓存的 getter 函数。没有 setter 时,它只响应数据变化、不接受外部赋值。强行写入会破坏响应式链路,所以运行时报错。
如何添加 setter 实现可写?
只需把计算属性写成对象形式,显式定义 get 和 set 方法:
- get:返回派生值(必须有)
- set:接收新值,并反向更新源数据(比如修改
data或ref)
示例(Vue 3 Composition API):
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
get() {
return `${firstName.value} ${lastName.value}`
},
set(newValue) {
const parts = newValue.split(' ')
firstName.value = parts[0] || ''
lastName.value = parts[1] || ''
}
})
这样 fullName 就能用于 <input v-model="fullName">,输入时自动拆分并更新 firstName 和 lastName。
常见错误与避坑提示
- 忘记写
get:setter 必须配合 getter,否则无法读取初始值 - 在
set中修改了错误的响应式源:确保更新的是原始响应式变量(如ref或reactive的属性),而不是计算出的中间值 - 误用在非响应式数据上:如果源数据不是
ref/reactive,setter 更新不会触发视图刷新 - Vue 2 写法略有不同:使用
computed: { fullName: { get() {}, set() {} } }对象语法,逻辑一致
什么场景更适合用 computed setter?
适合「一个输入由多个字段组合、同时又需要被整体编辑」的场景,比如:
- 表单中「全名」字段 ↔ 拆分为「姓」+「名」存储
- 「价格」显示为带货币符号的字符串 ↔ 编辑时只输入数字,自动补符号和格式
- URL 路径字符串 ↔ 解析为
protocol、host、path等字段
注意:若逻辑复杂或涉及异步、校验、副作用,建议改用普通方法 + 监听器(watch),避免把业务逻辑塞进 set 中。