import { defineStore } from 'pinia'; import { ref } from 'vue'; export const useAudioStore = defineStore('audioStore', { state: () => ({ // 音频实例(全局唯一) audioInstance: null, // 当前播放状态 isPlaying: false, // 当前播放的音频地址 currentSrc: '', // 加载状态 isLoading: false, // 错误信息 errorMsg: '', callbacks: { onEnded: {}, // 播放完成回调 onError: {}, // 播放错误回调 onLoaded: {} // 音频加载完成回调(可获取时长) } }), getters: { // 获取当前音频实例(简化外部调用) getAudioInstance(state) { return state.audioInstance; }, // 检查是否正在播放 isAudioPlaying(state) { return state.isPlaying; } }, actions: { // 初始化音频实例(确保全局唯一) initAudio(audioId) { if (!this.audioInstance) { // 创建实例 this.audioInstance = uni.createInnerAudioContext(); // 绑定事件监听 this.bindAudioEvents(audioId); } return this.audioInstance; }, // 绑定音频事件(统一管理生命周期) bindAudioEvents(audioId) { if (!this.audioInstance) return; // 播放开始事件 this.audioInstance.onPlay(() => { this.isPlaying = true; this.isLoading = false; this.errorMsg = ''; }); // 播放结束事件 this.audioInstance.onEnded(() => { this.resetAudioState(); // 触发自定义回调 if (this.callbacks.onEnded[audioId] && typeof this.callbacks.onEnded[audioId] === 'function') { this.callbacks.onEnded[audioId](); } }); // 音频可以播放时触发(此时通常能获取到时长) this.audioInstance.onCanplay(() => { // 尝试获取时长(部分环境需要延迟一点) // console.log('尝试获取时长(部分环境需要延迟一点)'); setTimeout(() => { const duration = this.audioInstance.duration || 0; console.log('尝试获duration', duration); if (duration > 0) { this.duration = duration; this.isLoaded = true; this.isLoading = false; if (this.callbacks.onLoaded[audioId] && typeof this.callbacks.onLoaded[ audioId] === 'function') { this.callbacks.onLoaded[audioId]({ duration: this.duration }); } } }, 100); // 短暂延迟确保时长已加载 }); // 加载完成事件 this.audioInstance.onCanplay(() => { this.isLoading = false; }); // 错误事件 this.audioInstance.onError((err) => { this.isPlaying = false; this.isLoading = false; this.errorMsg = `播放错误: ${err.errMsg || '未知错误'}`; console.error('音频错误:', err); if (this.callbacks.onError[audioId] && typeof this.callbacks.onError[audioId] === 'function') { this.callbacks.onError[audioId](this.errorMsg); // 把错误信息传给外部 } }); }, // 新增:预设置音频地址并加载(此时不播放,仅获取时长) setAudioSrc(src, audioId) { console.log('预设置音频地址并加载(此时不播放,仅获取时长)', src); if (!src || src === this.currentSrc) return; // 地址不变则不重复加载 this.initAudio(audioId); this.isLoading = true; this.isLoaded = false; // 重置加载状态 this.currentSrc = src; this.errorMsg = ''; try { // 先停止当前播放并清空旧地址 // this.audioInstance.stop(); // this.audioInstance.src = ''; // 设置新地址并加载(不自动播放) this.audioInstance.src = src; // this.audioInstance.load(); // 手动触发加载 } catch (err) { this.isLoading = false; this.errorMsg = `设置音频失败: ${err.message}`; } }, // 修改:播放当前已设置的音频(需先调用setAudioSrc) playAudio() { if (!this.currentSrc) { this.errorMsg = '请先设置音频地址'; return; } // 已在播放则暂停 console.log('已在播放则暂停', this.isPlaying); if (this.isPlaying) { this.pauseAudio(); return; } console.log('未加载完成则等待加载', this.isLoaded); // 未加载完成则等待加载 if (!this.isLoaded) { this.isLoading = true; return; } // 执行播放 try { this.audioInstance.play(); this.isPlaying = true; this.isLoading = false; } catch (err) { this.isLoading = false; this.errorMsg = `播放失败: ${err.message}`; } }, // 暂停播放 pauseAudio() { if (this.audioInstance && this.isPlaying) { this.audioInstance.pause(); this.isPlaying = false; } }, // 停止播放并重置状态 stopAudio() { if (this.audioInstance) { this.audioInstance.stop(); this.resetAudioState(); } }, // 重置音频状态(保留实例,清空状态) resetAudioState() { this.isPlaying = false; this.isLoading = false; // this.currentSrc = ''; // 清空地址避免残留 if (this.audioInstance) { this.audioInstance.src = ''; } }, // 销毁音频实例(页面卸载时调用) destroyAudio() { if (this.audioInstance) { // 移除所有事件监听 this.audioInstance.offPlay(); this.audioInstance.offEnded(); this.audioInstance.offCanplay(); this.audioInstance.offError(); // 停止并销毁实例 this.audioInstance.stop(); this.audioInstance.destroy(); // 重置所有状态 this.audioInstance = null; this.resetAudioState(); this.errorMsg = ''; } }, // 移除所有回调(组件卸载时调用) removeCallbacks(audioId) { this.callbacks.onEnded[audioId] = null; this.callbacks.onError[audioId] = null; this.callbacks.onLoaded[audioId] = null; }, // 注册播放完成回调 onAudioEnded(callback, audioId) { if (typeof callback === 'function') { this.callbacks.onEnded[audioId] = callback; } }, // 注册播放错误回调 onAudioError(callback, audioId) { if (typeof callback === 'function') { this.callbacks.onError[audioId] = callback; } }, // 新增:注册音频加载完成回调(用于获取时长) onAudioLoaded(callback, audioId) { if (typeof callback === 'function') { this.callbacks.onLoaded[audioId] = callback; } }, } }); export const useAudioFun = (audioId) => { const audioStore = useAudioStore(); return { // 播放:忽略res参数,直接使用绑定的audioId playAudio: (res) => audioStore.playAudio(audioId), // 停止:无参数,直接调用 stopAudio: () => audioStore.stopAudio(), // 移除回调:需要组件key,绑定audioId removeCallbacks: () => audioStore.removeCallbacks(audioId), // 设置音频源:第一个参数是src,自动绑定audioId setAudioSrc: (src) => audioStore.setAudioSrc(src, audioId), // 注册结束回调:第一个参数是回调,第二个是组件key,自动绑定audioId onAudioEnded: (callback) => audioStore.onAudioEnded(callback, audioId), // 注册错误回调:同上 onAudioError: (callback) => audioStore.onAudioError(callback, audioId), // 注册加载完成回调:同上 onAudioLoaded: (callback) => audioStore.onAudioLoaded(callback, audioId) }; };