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

