audio报错DOMException: play() failed because the user didn‘t interact with the document first
封装一个包含自动播放,循环播放、暂停功能的Aduio组件
·
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<any> {
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对象
// 如果在声音播放前未进行交互,出现提示框,让用户点击
<transition name="audio-notify-fade">
<el-card v-show="isShwoAudioNofify" class="audio-notify-box-card" id="audio-notify">
<div class="title">
<i class="el-icon-warning"></i>
<span> 提示 </span>
</div>
<div class="content">请开启声音自动播放</div>
<div class="footer">
<el-button size="mini" type="warning" @click="hiddenAudioNofity">确定</el-button>
</div>
</el-card>
</transition>
// 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
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)