0

我正在将一个项目从 Vue2 迁移到 3,并试图了解在组件数据上创建字段时出现的错误。使用 ToneJS,我可以new Synth()在方法体中或在 created 钩子中创建一个,然后在我的playNote方法中调用它。但是,当合成器定义为 上的字段时data,单击“播放”按钮时出现以下错误。

在 Vue2 中我没有这样的问题。想知道是否有人可以解释这里发生了什么?为什么创建的钩子有效但数据字段无效?

感谢您对此的任何帮助!错误的全文:

runtime-core.esm-bundler.js?5c40:6568 [Vue 警告]:在 <Main onVnodeUnmounted=fn ref=Ref< Proxy {playNote: ƒ, ...} >> at warn @ 处执行本机事件处理程序期间出现未处理错误runtime-core.esm-bundler.js?5c40:6568 logError @ runtime-core.esm-bundler.js?5c40:6742 handleError @ runtime-core.esm-bundler.js?5c40:6734 eval @ runtime-core.esm -bundler.js?5c40:6697 Promise.catch (async) callWithAsyncErrorHandling@runtime-core.esm-bundler.js?5c40:6696 调用者@runtime-dom.esm-bundler.js?830f:347 localhost/:1 未捕获(承诺)DOMException

<template>    
<div>      
<button v-on:click="playNote">Play</button>    
</div>  
</template>   
<script lang="ts">  
import { defineComponent } from "vue";      
import * as Tone from 'tone'  

export default defineComponent({          
  name: "Main",          
  data() {              
    return {  
      synth: new Tone.Synth().toDestination(), // this throws an error 
      playing: false, 
    }
  },          
  methods: {              
    async playNote(){  
      console.log('playNote'); // logs properly await Tone.start();          
      console.log('this.synth', this.synth); // synth object logs        
      this.synth.triggerAttackRelease('C4', '8n');                   
    
      // this works:            
      // const synth = new Tone.Synth().toDestination();        
      // synth.triggerAttackRelease('C4', '8n');              
    },          
  },   
  created() {     
    // this.synth = new Tone.Synth().toDestination() // this also works   
  }    
});      
</script>
4

1 回答 1

0

在 Vue 3 中,Vue 使用Proxy来跟踪对象的更改(Vue 2 使用Object.defineProperty)。

当我们从组件的数据函数返回一个普通的 JavaScript 对象时,Vue 会将该对象包装在一个代理中,并带有用于获取和设置的处理程序。

来自Vue 如何跟踪这些变化

经过调试,我发现错误来自一个名为get-native-contextfrom standardized-audio-contextpackage 的文件,如果找不到某个上下文变量,则会抛出错误:

export const createGetNativeContext = (contextStore) => {
    return (context) => {
        const nativeContext = contextStore.get(context); // contextStore is a WeakMap
        if (nativeContext === undefined) {
            throw createInvalidStateError();
        }
        return (nativeContext);
    };
};

原始文件在这里

所以我的猜测是在库中的某个地方存储 Synth 上下文对象 ( synth.context._context) 以供以后使用。但是 Synth 上下文对象已更改为 Proxy。当它试图通过它获取上下文时,contextStore.get(context)它会返回undefined.

从您的代码:

created() {     
    this.synth = new Tone.Synth().toDestination()
}

这是有效的,因为this.synth它只是一个普通的对象而不是反应性的(代理)。

如果您不需要synth对象具有反应性,则您的代码在方法和创建的钩子中都很好。但是,如果您希望它具有反应性,则必须以某种方式包装它。

例如:

...
  data() {
    return {
      synth: () => new Tone.Synth().toDestination()
    }
  },
  methods: {
    async playNote() {
      this.synth().triggerAttackRelease('C4', '8n')
    }
  }
...

这不是一个很好的例子,因为synth每次使用它都会创建。 JSFiddle

于 2021-11-01T07:46:22.457 回答