Vue 报警自动播放音效

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>
相关推荐
高级程序源4 小时前
django校园寻物通失物招领平台32261-计算机课程设计、毕业设计
vue.js·python·mysql·小程序·django·flask·课程设计
WeiXin_DZbishe4 小时前
基于springboot宠物领养系统-计算机毕设 附源码【课程设计】94217
vue.js·spring boot·python·django·php·课程设计
架构技术专栏5 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
别动我齐刘海5 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
志尊宝6 小时前
Vue3 零基础每日笔记(071):暗黑模式与主题切换——CSS 变量 + Element Plus 暗黑方案
前端·css·笔记·vue·html·前端开发·软件开发
WeiXin_DZbishe7 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
刘发财7 小时前
前端如何生成10000页PDF文件?
前端·javascript·开源
WeiXin_DZbishe7 小时前
基于Springboot+AI的kuall音乐广场的设计与实现-计算机毕设 附源码【课程设计】12715
vue.js·人工智能·spring boot·后端·python·php·课程设计
A接拉起0077 小时前
2026 年 JavaScript 开发者需要了解的知识
前端·javascript·后端
_馒头7 小时前
pixiJs游戏开发实践 - 跳棋小游戏
javascript·vue.js