• 封装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樱释ღ( ´・ᴗ・` )

    打不死的小强
  • 相关阅读:
    java两个栈实现一个队列&&两个队列实现一个栈
    Java HashSet和ArrayList的查找Contains()时间复杂度
    Java KMP算法代码
    利用集合求取字符串里每个字符的个数
    快速失败and安全失败
    Java 巴什博弈(取石子报数问题)
    [知识点][施工中] 1.1 部分IDE介绍
    [知识点] 4.4 动态规划进阶模型——树形/DAG/数位DP
    [知识点] 4.3 动态规划基础模型——区间DP/LIS/LCS
    [课堂小笔记] 数字电子技术
  • 原文地址:https://www.cnblogs.com/mggahui/p/13461094.html
Copyright © 2020-2023  润新知