Vue 2中触发getter属性isRequired重新计算的原因是什么?
问题场景
你在Vue 2开发中遇到的现象:组件通过v-show绑定了getter属性isRequired,代码如下:
<my-component v-show="isRequired"> public get isRequired(): boolean { if(this.model.myBooleanProperty && this.model.myNumberProperty > 0) { return true; } if(this.model.myOtherBooleanProperty && this.model.myOtherNumberProperty > 0) { return true; } return false; }
实际测试发现,myBooleanProperty、myNumberProperty、myOtherBooleanProperty的变化能触发isRequired重计算,但myOtherNumberProperty的变化始终无法触发,即使修改判断逻辑也无效。
核心原理:Vue 2的响应式依赖收集
Vue 2基于Object.defineProperty实现响应式系统,计算属性(包括模板绑定的getter属性)的依赖收集逻辑是:
- 当getter首次执行时,Vue会追踪所有被读取到的响应式属性,将这些属性标记为该getter的依赖。
- 后续只有这些被收集的依赖发生变化时,才会触发getter的重新计算,进而更新视图(比如
v-show的状态)。
你的场景具体分析
问题出在逻辑短路特性上:
第二个if判断中使用了&&逻辑运算符,当this.model.myOtherBooleanProperty为false时,&&右侧的this.model.myOtherNumberProperty > 0不会被执行——也就是说,myOtherNumberProperty根本没有被读取到。
如果组件首次渲染时myOtherBooleanProperty是false,Vue的依赖收集机制就不会把myOtherNumberProperty加入到isRequired的依赖列表中。后续即使myOtherNumberProperty变化,因为它不在依赖列表里,自然不会触发isRequired的重计算。
哪怕你移除前面的判断逻辑,只要首次计算时myOtherBooleanProperty还是false,myOtherNumberProperty依旧不会被访问,依赖收集还是不会生效。而你说的“直接修改它的值”也没用,因为依赖收集只监听读取操作,修改操作不会触发依赖收集。
触发重计算的明确条件
Vue触发isRequired重新计算的核心条件是:该getter在首次执行过程中被读取到的响应式属性发生变化。
要让myOtherNumberProperty触发重计算,你需要确保它在getter执行时一定会被读取,比如提前单独读取该属性,避免逻辑短路:
public get isRequired(): boolean { // 提前读取,确保被收集为依赖 const otherNumber = this.model.myOtherNumberProperty; if(this.model.myBooleanProperty && this.model.myNumberProperty > 0) { return true; } if(this.model.myOtherBooleanProperty && otherNumber > 0) { return true; } return false; }
这样不管myOtherBooleanProperty初始值是什么,myOtherNumberProperty都会被读取,从而被加入依赖列表,后续变化时就能触发isRequired的重计算。
内容的提问来源于stack exchange,提问作者Bob Tway

