Vue 报警自动播放音效
抽取音频工具类(utils/audioAlarm.js)
将报警音效(如 alarm.mp3,建议短音频 < 3 秒)放入项目 public 文件夹(打包后路径为 /alarm.mp3)。
js
/**
* 报警音效工具类
* 解决浏览器自动播放限制,支持报警音效自动播放、循环播放、资源清理
*/
class AudioAlarm {
constructor(options = {}) {
// 配置项
this.config = {
soundUrl: '/alarm.mp3', // 音效文件路径(public 下)
volume: 1, // 音量 0-1
loop: false, // 是否循环播放
...options
};
// 状态管理
this.audioInstance = null; // 音频实例
this.isAuthorized = false; // 是否完成用户交互授权
this.isPlaying = false; // 是否正在播放
this.authListener = null; // 授权事件监听函数
}
/**
* 初始化音频并完成用户授权(突破自动播放限制)
* 自动绑定全局点击事件,用户首次点击后完成授权
*/
init() {
// 已授权则直接返回
if (this.isAuthorized) return;
// 创建音频实例并预加载
this.audioInstance = new Audio(this.config.soundUrl);
this.audioInstance.volume = this.config.volume;
this.audioInstance.load();
// 绑定全局点击授权(仅触发一次)
this.authListener = () => this._authorize();
document.addEventListener('click', this.authListener, { once: true });
document.addEventListener('touchstart', this.authListener, { once: true }); // 兼容移动端
}
/**
* 内部方法:完成音频授权(静音播放一次)
*/
_authorize() {
if (this.isAuthorized || !this.audioInstance) return;
// 静音播放完成授权(用户无感知)
this.audioInstance.muted = true;
this.audioInstance.play()
.then(() => {
this.audioInstance.pause();
this.audioInstance.muted = false;
this.isAuthorized = true;
console.log('音频授权成功,后续可自动播放');
})
.catch(err => {
console.warn('音频授权失败:', err);
});
}
/**
* 播放报警音效(授权后自动触发)
*/
play() {
if (!this.isAuthorized || !this.audioInstance || this.isPlaying) return;
try {
// 重置播放位置,避免卡顿
this.audioInstance.currentTime = 0;
// 播放音效
this.audioInstance.play();
this.isPlaying = true;
// 循环播放逻辑
if (this.config.loop) {
this.audioInstance.onended = () => {
this.audioInstance.currentTime = 0;
this.audioInstance.play();
};
} else {
this.audioInstance.onended = () => {
this.isPlaying = false;
};
}
} catch (err) {
console.error('音效播放失败:', err);
this.isPlaying = false;
this.isAuthorized = false; // 授权失效,重新授权
this.init(); // 重新初始化
}
}
/**
* 停止播放音效
*/
stop() {
if (!this.audioInstance || !this.isPlaying) return;
this.audioInstance.pause();
this.audioInstance.currentTime = 0;
this.isPlaying = false;
this.audioInstance.onended = null; // 清除循环监听
}
/**
* 销毁音频实例(组件卸载时调用)
*/
destroy() {
this.stop();
this.audioInstance = null;
this.isAuthorized = false;
if (this.authListener) {
document.removeEventListener('click', this.authListener);
document.removeEventListener('touchstart', this.authListener);
this.authListener = null;
}
}
}
export default new AudioAlarm();
组件中使用工具类
html
<template>
<div class="alarm-page">
</div>
</template>
<script>
import axios from 'axios';
import audioAlarm from '@/utils/audioAlarm'; // 导入音频工具类
export default {
name: 'AlarmPage',
data() {
return {
hasAlarm: false,
alarmMsg: '',
pollTimer: null
};
},
created() {
// 初始化音频工具(自动绑定授权事件)
audioAlarm.init();
},
methods: {
// 请求报警接口
async fetchAlarmStatus() {
try {
const res = await axios.get('/api/alarm/status');
const { isAlarm, msg } = res.data;
// 有报警:播放音效
if (isAlarm && !this.hasAlarm) {
this.hasAlarm = true;
this.alarmMsg = msg;
audioAlarm.play(); // 调用工具类播放音效
}
// 报警解除:停止音效
if (!isAlarm && this.hasAlarm) {
this.hasAlarm = false;
this.alarmMsg = '';
audioAlarm.stop(); // 调用工具类停止音效
}
} catch (err) {
console.error('获取报警状态失败:', err);
}
},
// 启动接口轮询
startPolling() {
this.fetchAlarmStatus();
this.pollTimer = setInterval(this.fetchAlarmStatus, 5000);
}
},
mounted() {
this.startPolling();
},
beforeDestroy() {
// 清理资源
clearInterval(this.pollTimer);
audioAlarm.destroy(); // 销毁音频实例
}
};
</script>