封装web audio 音频播放类

使用h5 audio api播放音频

获取audio 的3种方式
1,使用浏览器提供的原生对象

const audio = new Audio()

2,创建音频标签的形式

const audio = document.createElement('audio')

3,html页面直接使用音频标签然后通过js代码获取

<audio id="audio"></audio>
<script>
    const audio = document.getElementById('audio')
</script>

audio元素的属性及方法在这里不多加讲解,详情请自行参考api文档(也可以点击这里哟)

选用第1种方式来操作音频实现代码如下:

class EventBus {
    // 事件缓存对象
    events = Object.create(null)
    constructor() { }
    // 获取监听器
    getListeners(type) {
        return this.events[type] = this.events[type] || []
    }
    // 添加监听事件
    on(type, fn) {
        const listeners = this.getListeners(type)
        // 同一个方法仅允许被添加一次
        if (!listeners.includes(fn)) {
            listeners.push(fn)
        }
    }
    // 移除监听事件
    off(type, fn) {
        const listeners = this.getListeners(type)
        const index = listeners.indexOf(fn)
        if (index < -1) {
            return
        } else {
            listeners.splice(index, 1)
        }
    }
    // 移除所有监听器
    removeAll(type) {
        this.events[type] = []
    }
    // 触发监听事件
    fire(type, ...args) {
        this.getListeners(type).forEach(fn => fn(...args))
    }
}
/**
 * 后台播放音频类
 */
class BGAudio extends EventBus {
    // 音频标签
    audio = null
    // 播放音频地址
    audioUrl = null
    // 可以添加的有效音频相关事件名称
    // 事件存在兼容性问题
    validEvents = [
        'loadstart', // 客户端开始请求数据
        'progress', // 客户端正在请求数据(或者说正在缓冲)
        'play', // play()和autoplay播放时
        'pause', // pause()方法触发时
        'ended', // 当前播放结束
        'timeupdate', //当前播放时间发生改变的时候
        'canplaythrough', //歌曲已经载入完全完成
        'canplay', // 缓冲至目前可播放状态
        'onloadedmetadata', // 当元数据(比如分辨率和时长)被加载时
        'error', // 播放出错
    ]
    // 播放状态 pending(待定)  playing(播放中)  pausing(暂停中)
    playStatus = 'pending' // 待定状态
    CONSTANT = {
        pending: 'pending',
        playing: 'playing',
        pausing: 'pausing',
    }
    constructor(config = {}) {
        super()
        this.audioUrl = config.audioUrl
        this.audio = new Audio()
        const onEvents = config.on || {}
        Object.keys(onEvents).forEach((name) => {
            this.on(name, onEvents[name])
        })
        this.on('error', () => {
            this.stop()
        })
    }
    // 是否有效事件名称
    isValidEventName(eventName) {
        return this.validEvents.includes(eventName)
    }
    // 添加监听器
    on(type, handler) {
        super.on(type, handler)
        this.audio.addEventListener(type, handler, false)
    }
    // 移除监听器
    off(type, handler) {
        this.remove(type, handler)
    }
    // 移除监听器,当fn不存在时,移除type所有监听器
    remove(type, handler) {
        if (handler) {
            super.off(type, handler)
            this.audio.removeEventListener(type, handler, false)
        } else {
            this.getListeners(type).forEach((fn) => {
                this.audio.removeEventListener(type, fn, false)
            })
            super.removeAll(type)
        }
    }

    /**
     * 播放相关
     */
    // 设置音频地址
    setAudioUrl(url) {
        this.audioUrl = url
    }
    // 设置播放状态标志
    setPlayStatus(status) {
        this.playStatus = status
    }
    // 播放,可传递音频地址
    play(url) {
        const originUrl = this.audioUrl
        if (url) {
            // url存在则使用新地址
            this.setAudioUrl(url)
        }
        // 存在音频地址才播放
        if (!this.audioUrl) {
            return
        }
        const audio = this.audio
        //处于暂停状态才需要播放
        if (audio.paused) {
            this.setPlayStatus(this.CONSTANT.playing)
            // 地址变化的时候才需要重新赋值,因为重新赋值会导致刷新操作
            if (originUrl !== this.audioUrl || !this.audio.src) {
                this.audio.src = this.audioUrl
            }
            this.audio.play()
        }
    }
    // 按进度播放
    playByRate(playRate) {
        if (playRate < 0 || playRate > 100) {
            playRate = 0
        } else if (playRate > 100) {
            playRate = 100
        }
        playRate = playRate / 100
        this.playByTime(this.audio.duration * playRate)
    }
    // 按时间播放
    playByTime(time) {
        const audio = this.audio
        if (time < 0) {
            time = 0
        } else if (time > audio.duration) {
            time = audio.duration
        }
        audio.currentTime = time
        this.play()
    }
    // 暂停
    pause() {
        this.setPlayStatus(this.CONSTANT.pausing)
        this.audio.pause()
    }
    // 停止
    stop() {
        this.playByTime(0)
        this.pause()
        this.setPlayStatus(this.CONSTANT.pending)
    }
    // 播放与暂停切换
    togglePlay() {
        if (this.playStatus === this.CONSTANT.playing) {
            this.pause()
        } else {
            this.play()
        }
    }
    // 重新加载
    reload() {
        this.setPlayStatus(this.CONSTANT.pending)
        this.audio.load()
    }
}
BGAudio

在这里我自行实现封装了事件接口(EventBus),实现了基本的事件发布订阅功能,BGAudio类继承了EventBus类,以方便对封装的音频类进行自定义扩展操作,当然,你也可以选择不继承EventBus类 ,因为获取到的audio对象本身实现了标准浏览器事件接口EventTarget

音频事件

常用音频事件,如下图所示

BGAudio类实现功能如下:

①,提供事件接口监听音频事件及html标准事件

  on(type,handler) 方法添加监听器

  off(type,handler) 方法移除监听器

  fire(type,[data1,data2,...]) 方法触发监听器,对于自定义事件可使用该方法触发并传递自定义数据,对于音频audio原生事件使用该方法触发无效(因为没有event事件对象数据)

添加监听事件可以在创建实例的时候通过参数config 的 on 字段添加 监听事件,也可以在初始化实例后调用on方法添加,示例代码如下:

 上述两种初始化监听器方式实际使用时二者选一即可。

 ②,简单记录当前播放状态信息,除了播放和暂停状态,其他均为待定状态 (对于错误状态,后期通过自定义错误码errorCode来标识错误,暂未实现)

 ③,提供音频播放相关操作

  play(url) 播放音频

  pause()  暂停播放

  stop() 停止播放(即将播放进度归零)

  togglePlay() 播放与暂停之间切换

  playByTime() 按照时间点进行播放

  playByRate() 按照进度(0-100)播放

api仅仅提供了常用的播放操作,没有封装页面样式相关

@萍2樱释ღ( ´・ᴗ・` )

打不死的小强
原文地址:https://www.cnblogs.com/mggahui/p/13461094.html