封裝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櫻釋ღ( ´・ᴗ・` )


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM