【问题标题】:Vue3: Object instantiation in created hook vs data fieldVue3:创建的钩子与数据字段中的对象实例化
【发布时间】:2021-10-31 17:04:57
【问题描述】:

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

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

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

runtime-core.esm-bundler.js?5c40:6568 [Vue 警告]:执行本机事件处理程序期间出现未处理错误 在

> 在 在 警告@runtime-core.esm-bundler.js?5c40:6568 logError @ runtime-core.esm-bundler.js?5c40:6742 处理错误@runtime-core.esm-bundler.js?5c40:6734 eval @ runtime-core.esm-bundler.js?5c40:6697 Promise.catch(异步) 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>

【问题讨论】:

    标签: vuejs3 tonejs


    【解决方案1】:

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

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

    来自How Vue Tracks These Changes

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

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

    原始文件为here

    所以我的猜测是在库中的某个地方存储 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

    【讨论】:

    • 感谢您的澄清。每次都创建一个新的合成器似乎会产生音频性能(即:时序)问题。你知道是不是这样吗? (有时性能考虑是违反直觉的。)
    • @drenl 对不起,我没有这方面的经验。
    猜你喜欢
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    相关资源
    最近更新 更多