You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebAudio API异步事件:如何在振荡器停止播放后触发事件?

嘿,这个问题其实很好解决——Web Audio API里的振荡器(OscillatorNode)属于AudioScheduledSourceNode类型,它自带了一个onended事件,专门用来监听节点停止播放的时刻。结合Vue的响应式系统,你可以轻松实现停止时更新DOM的需求。

下面是完整的Vue组件示例,我会把关键逻辑标注清楚:

<template>
  <div id="player">
    <div>当前播放时长: {{ currentTime }}</div>
    <button @click="start">Play Note</button>
    <div>播放序列: {{ sequence.join(', ') }}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      currentTime: 0,
      sequence: [],
      audioContext: null,
      oscillator: null,
      startTime: 0
    };
  },
  mounted() {
    // 提前初始化音频上下文,避免用户首次点击时的延迟
    this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
  },
  methods: {
    async start() {
      // 浏览器安全限制:必须通过用户交互激活音频上下文
      if (this.audioContext.state === 'suspended') {
        await this.audioContext.resume();
      }

      // 清理之前的振荡器实例,避免多个声音叠加或内存泄漏
      if (this.oscillator) {
        this.oscillator.stop();
        this.oscillator.disconnect();
      }

      // 创建新的振荡器
      this.oscillator = this.audioContext.createOscillator();
      this.oscillator.type = 'sine'; // 设置波形类型(sine/square/triangle/sawtooth)
      this.oscillator.frequency.value = 440; // 设置音高(A4标准音)

      // 核心:绑定振荡器停止事件
      this.oscillator.onended = () => {
        // 计算实际播放时长
        const playDuration = this.audioContext.currentTime - this.startTime;
        this.currentTime = playDuration.toFixed(2);
        // 将播放记录添加到序列中
        this.sequence.push(`A4 (${playDuration.toFixed(2)}s)`);
        // 清空振荡器引用
        this.oscillator = null;
      };

      // 将振荡器连接到音频输出设备
      this.oscillator.connect(this.audioContext.destination);
      // 记录播放开始时间
      this.startTime = this.audioContext.currentTime;
      // 启动振荡器,并设置1秒后自动停止
      this.oscillator.start();
      this.oscillator.stop(this.audioContext.currentTime + 1);
    }
  }
};
</script>

关键逻辑说明:

  1. onended事件的作用:这是Web Audio API内置的事件,当振荡器播放结束(无论是主动调用stop()还是到达预定停止时间)时会自动触发。在回调函数里修改Vue的响应式数据,DOM会自动同步更新。
  2. 音频上下文激活:现代浏览器禁止自动播放音频,必须通过用户交互(比如点击按钮)激活AudioContext,所以在start方法里先检查并恢复上下文状态。
  3. 振荡器实例管理:每次创建新振荡器前,停止并断开旧实例,防止多个声音同时播放或内存泄漏。
  4. 精准时长计算:利用audioContext.currentTime(音频上下文的独立时间轴)计算播放时长,比用Date更准确,不受系统时间影响。

内容的提问来源于stack exchange,提问作者David J.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:36:58