Vue如何实现自定义类实例属性变更后触发视图更新
问题原因
- 你当前创建的
Stopwatch是普通类实例,没有被Vue的响应式系统代理,实例内部属性变更时Vue无法感知,自然不会触发视图更新 - 你使用
computed包裹类实例的写法属于API误用,computed适用于依赖其他响应式变量动态计算值的场景,这里不需要额外包裹
最优解决方案(无侵入,类代码无需修改)
直接用reactive包裹类实例即可,修改main.vue的setup逻辑:
<script lang="ts"> import { defineComponent, reactive } from '@vue/composition-api'; import Stopwatch from 'src/utils/stopwatch'; export default defineComponent({ // 注意修改组件名,避免和导入的Stopwatch类重名冲突 name: 'StopwatchPage', setup() { // 用reactive包裹类实例,让实例属性变为响应式 const sw = reactive(new Stopwatch()); return { sw }; } }); </script>
方案说明
reactive会将普通类实例转为Vue的响应式代理对象,所有在constructor中提前声明的属性变更都会被Vue跟踪,自动触发视图更新- 类的原有方法完全不需要修改,方法内修改
this属性的逻辑会自动作用于响应式代理对象,变更可被正常捕获
备选方案(类与Vue耦合,适合仅在Vue项目中使用的场景)
如果你接受类和Vue响应式API绑定,可以直接在类内部用ref声明响应式属性,无需在使用时包裹:
修改stopwatch.ts:
import { ref } from '@vue/composition-api' export default class Stopwatch { // 直接用ref定义响应式属性 isPlaying = ref<boolean>(false); constructor() {} startTimer() { this.isPlaying.value = true; console.log('play'); } stopTimer() { this.isPlaying.value = false; console.log('stop'); } toggle() { if (this.isPlaying.value) { this.stopTimer(); } else { this.startTimer(); } } }
对应的main.vue里直接初始化实例即可:
setup() { const sw = new Stopwatch(); return { sw }; }
注意事项
如果后续要给Stopwatch类扩展新属性,必须在类的constructor中提前声明该属性的初始值,否则Vue2的响应式系统无法跟踪后续新增的属性变更。
内容的提问来源于stack exchange,提问作者JokerMartini
相关产品推荐
相关产品推荐

