Vue3中data内实例化ToneJS Synth报错而created钩子正常的原因
问题原因
核心问题是Vue3响应式机制和ToneJS实例的兼容性冲突:
- Vue3的响应式基于ES6 Proxy实现,所有定义在
data函数返回值中的对象,都会被递归包装为响应式Proxy对象,默认拦截对象所有属性的读取、修改操作。 - ToneJS的
Synth实例内部包含大量Web Audio API原生节点、上下文对象,这些原生对象存在大量不可配置的内置属性、依赖固定的内部this指向,被Proxy代理后,Tone内部访问属性的逻辑会被破坏,最终触发DOMException错误。方法内局部实例化的Synth不会被Vue响应式系统处理,因此运行正常。 - Vue2的响应式基于
Object.defineProperty实现,只会劫持对象表层的已有属性,不会将整个实例递归转为代理对象,对第三方类实例的侵入性更低,因此不会触发该问题。
为什么created钩子赋值可行?
你在created钩子中直接给this.synth赋值时,只要data函数中没有提前声明synth字段,Vue3不会主动将这个挂载到实例上的属性转为响应式,Tone实例没有被Proxy包装,内部逻辑可以正常运行。
解决方案
如果需要将Tone实例作为实例属性长期存储,可选用以下两种方案:
- 方案1:使用
markRaw标记Tone实例不被响应式系统代理,再放入data中:
import { defineComponent, markRaw } from "vue"; // ... data() { return { synth: markRaw(new Tone.Synth().toDestination()), playing: false, } }
- 方案2:不在
data中声明synth字段,直接在created钩子中挂载到实例上即可,不需要额外处理。
内容的提问来源于stack exchange,提问作者drenl
相关产品推荐
相关产品推荐

