audio报错DOMException: play() failed because the user didn‘t interact with the document first

chrome66版本之后禁掉了声音的自动播放,这句报错提示,调用play方法之前,请先与页面进行交互。
我们自己来封装一个可以自动播放的Audio,功能包含:自动播放、暂停、循环播放。
1、封装一个audio对象

export class Audio {
    private _audio: HTMLAudioElement
    private _source: HTMLElement
    playSoundSecond: number  // 播放时长,用来计算循环播放次数

    constructor(playSoundSecond) {
        this._audio = document.createElement('audio')
        this._audio.setAttribute("autoplay", "autoplay")
        this._source = document.createElement('source')
        this._audio.appendChild(this._source)
        document.body.appendChild(this._audio);
        this.playSoundSecond = playSoundSecond
    }
	
	// 计算循环播放次数
    async countAudioTime() {
        let _this = this
        while (isNaN(_this._audio.duration) || _this._audio.duration === Infinity) {
            // 延迟一会 不然网页都卡死
            await new Promise(resolve => setTimeout(resolve, 200));
            // 设置随机播放时间,模拟调进度条
            _this._audio.currentTime = 10000000 * Math.random()
        }
        // this._audio.duration 获取声音文件的时长
        if (this.playSoundSecond > Math.round(this._audio.duration)) {
            const count = Math.ceil(this.playSoundSecond / this._audio.duration)
            this._audio.setAttribute('loop', 'loop')  // 设置循环播放属性:loop
            let timer = null
            let i = 0
            timer = setInterval(()=>{
                i++
                if (i >= count) {
                    clearInterval(timer)
                    this._audio.removeAttribute('loop')
                    this.pause()
                }
            }, Math.round(this._audio.duration)*1000) 
        }
    }
    // 暂停
    pause() {
        if (this._audio.getAttribute('loop')) {
            this._audio.removeAttribute('loop')
        } 
        this._audio.pause()
    }
	// 初始化播放 传值一个声音文件地址
   init(fileName: string): Promise {
        let fileUrl = '/' + fileName
        this._source.setAttribute("src", fileUrl)
        this._audio.load()
        this._audio.autoplay = true;
        return new Promise((resolve, reject) => {
        	// 监测声音文件是否加载完毕
            this._audio.addEventListener("canplaythrough", event => {
            	// 都为4 说明网络稳定的状态下可播放声音文件
                if (this._audio.readyState == this._audio.HAVE_ENOUGH_DATA) {
                    this._audio.play()
                    .then(()=>{
                        console.log('声音播放成功');
                        this._audio.play()
                        resolve(undefined)
                    })
                    .catch((err)=>{
                        if (err.name == 'NotAllowedError') {
                            console.log('声音播放失败');
                            reject()
                        }
                    })
                }
            });
        })  
    }
}

2、实现Audio对象

// 如果在声音播放前未进行交互,出现提示框,让用户点击

   
        
提示
请开启声音自动播放
// ts部分 // 实现audio对象 get audio() { return new Audio(this.alarmConfig.playSoundSecond) } // 60s内如果页面没有任何click操作,出现提示框。 isShwoAudioNofify: boolean = false isHandleClick: boolean = false mounted() { this.initNotify() this.initAudio() } imitateClick() { this.isHandleClick = true if (this.isShwoAudioNofify) this.isShwoAudioNofify = false } initAudio() { document.addEventListener('click', this.imitateClick) let i = 0 let timer = setInterval(()=>{ i++ if (i == 60) { clearInterval(timer) window.removeEventListener('click', this.imitateClick) if (!this.isHandleClick) { this.isShwoAudioNofify = true } } },1000) } initNotify() { let audioNotify = document.getElementById('audio-notify') document.body.appendChild(audioNotify) } @Watch('audioFileName') watchFileName(newVal) { if (!!newVal) this.audioPlay(newVal) } // 播放方法 async audioPlay(fileName: string) { this.audio.countAudioTime() try { await this.audio.init(fileName) this.isPlayed = true } catch(err){ this.isShwoAudioNofify = true } }

你可能感兴趣的:(javascript,开发语言,vue,typescript,html)