Audio 標籤的使用和本身封裝一個強大的React音樂播放器

原文地址:https://www.dodoblog.cn/blog?id=5be84d5c70b2b617f27a4610git

 

這篇文章主要介紹一下博客裏的這個音樂播放器是怎麼寫的github

爲了更好的表達高深的東西,仍是須要先強調點簡單的東西 web

Audio元素的屬性

paused 是否暫停,不能夠修改ajax

audio.paused = true // 錯誤
audio.pause() // 正確

currentTime 當前播放的時間,也能夠用來改變進度,如下兩行代碼是等價的api

audio.currentTime = 10
audio.play(10)

duration 獲取當前加載好的音樂的時間數組

loop 是否單曲循魂dom

mute 是否靜音oop

volume 音量大小,數值是0 到 1 動畫

 

Audio元素的事件

play和pausethis

播放和暫停的時候觸發的事件

 

seeking和seeked

這裏的快進是時間忽然到某一個點上,不是倍速播放,快進開始和快進完成分別觸發一個不一樣事件,由於快進了可能須要加載數據,須要一點點時間

好比改變currentTime

 

loadstart,loadeddata和canplay

開始加,加載了一幀數據,加載到足夠播放的數據

 

ended

結束的時候,結束了播放下一首用

 

還有一些事件,好比progress, volumnchange 這些方法,隨便搜一下就能夠知道了,你們須要自行搜去,正常狀況下這些就夠用了。 

 

React播放器

參數

  <MusicPlayer
    getAudio={audio => this.audio = audio}
    musics={store.musicStore.currentList.songs}
  />

 

爲了方便啓用,核心的參數只有兩個

getAudio,和ref同樣,能夠返回當前的audio元素 musics是一個音樂的列表

由於在audio元素的基礎上開發,因此幾乎全部的事件其實也都是在audio上經過監聽獲取到,因此把audio元素拋出能夠減小不少配置

 

傳入一個數組 這個數組是一個音樂列表的信息

每一個對象應該包括 id,封面圖連接,歌曲連接,歌詞連接,歌唱家,歌曲名稱

 

樣式

 

我寫的這個播放器是這樣的,很簡單的樣子,基本功能都有,沒有循環播放和隨機播放的設置,其實也很簡單

 

 

 

 

這個播放器的主要元素包括

封面,歌曲列表,名稱,歌詞,進度,上一首下一首,還有封面上那個錢幣同樣的按鈕是播放暫停

而後側面的兩個按鈕能夠控制播放器的顯示隱藏和歌曲列表的顯示隱藏

具體的UI你們想象着寫就行了,反正我寫的也不算好看

 

留出那幾個控制的按鈕綁定事件就行了


初始化

  componentDidMount() {
    const musics = this.props.musics
    const audio = this.$audio.current
    this.setState({
      currentIndex: musics && musics.findIndex(item => item.id === window.localStorage.getItem('current-music-id')) || 0,
    })

    audio.addEventListener('play', this.handlePlay)
    audio.addEventListener('pause', this.handlePause)
    this.props.getAudio && this.props.getAudio(audio)
  }

 

初始化的時候,

1. 添加了事件監聽,這樣當外部改變audio的狀態也會改變播放器組件的狀態

2. 獲取localstorage裏的音樂,這個很友好,能夠刷新仍然是那一首歌

3. 拋出audio元素

 

播放和暫停

  handlePlay = () => {
    const music = this.props.musics[this.state.currentIndex]
    const audio = this.$audio.current

    this.handleLoadLrc()
    this.setState({ paused: false })

    window.localStorage.setItem('current-music-id', music.id)
    audio.play(audio.currentTime)

    this.timer = setInterval(() => {
      const { currentTime, duration } = audio
      this.setState({ currentTime, duration })
    }, 100)
  }

  handlePause = () => {
    this.setState({ paused: true })
    this.$audio.current.pause()
    this.timer && clearInterval(this.timer)
  }

 

注意

1. currentIndex表示當前的播放的音樂的index

2. 咱們設置了pause的屬性 是記錄播放器的當前狀態,audio的狀態改變不能實時反應去渲染dom,因此須要用本身的state記錄。

3. play須要傳入當前的audio時間,這樣暫停播放不會從新開始,而切換後currentTime也會歸0

4. 動態記錄了currentTime和duration,而且用計時器不對獲取,也是由於咱們並無辦法實時獲取時間反映到進度條上

 

上一首,下一首和切換

  handleNext = () => {
    let currentIndex = this.state.currentIndex + 1
    if (currentIndex >= this.props.musics.length) {
      currentIndex = 0
    }

    this.setState({currentIndex }, this.handlePlay)
  }

  handlePrev = () => {
    let currentIndex = this.state.currentIndex - 1
    if (currentIndex < 0) {
      currentIndex = this.props.musics.length - 1
    }

    this.setState({currentIndex }, this.handlePlay)
  }

  handleToggle = currentIndex => {
    this.setState({currentIndex }, this.handlePlay)
  }

 

 

上一首就是index - 1而後播放,若是index = 0 那麼index爲最後一個

下一首就是index +1而後播放,若是index已經最大 那麼index重置0

切換就是接受一個index 改變後播放

這三個超級簡單,很少解釋

 

快進

  handlePlayFrom = e => {
    const audio = this.$audio.current
    const { left, width } = e.target.getBoundingClientRect()
    const clickPos = (e.clientX - left) / width
    const time = audio.duration * clickPos
    if (!time) return false
    audio.currentTime = time
  }

 

 

這個稍微考驗些關於dom位置判斷的功底

經過獲取進度條的寬度,點擊的位置,而後計算出一個進度的百分比,最後根據這個百分比和總的音樂時長計算出點擊點的時間

 

加載歌詞

handleLoadLrc = () => {
    const request = new XMLHttpRequest();
    const url = this.props.musics[this.state.currentIndex].lrc
    request.open('GET', url, true);
    request.onload = () => {
      this.lyricStr = request.response
    }
    request.send();
  } 

播放的時候回去加載歌詞,就是一個ajax請求,返回的歌詞通常都是這樣的格式

 

 

看起來像個數組,實際上是一個字符串,而後咱們能夠經過正則將其拆分紅一個時間 歌詞一一對應的數組,這個是最麻煩的一點,但其實並無什麼技術複雜度,主要就是處理字符串經過split拆分紅數組就好

而後根據當前的currentTime獲取須要顯示的那句歌詞

不細節分析了,有須要的能夠在個人github上看

 

切換歌單

  componentDidUpdate(nextProps) {
    if (nextProps.musics !== this.props.musics) {
      this.setState({ currentIndex: 0 }, this.handlePlay)
    }
  }

 

當音樂列表發生改變的時候,從新播放就行了

 

播放器的顯示隱藏

動態添加一個class去隱藏整個播放器就好啦,fixed定位,很容易搞定的

播放器的基本功能就這麼多啦,固然還有一些,好比設置播放模式,依次仍是隨機,是否單曲循環等等,這些其實都很簡單。

 

具體的代碼

戳這裏 獲取播放器的代碼,有須要的自取

 

總結,在audio元素的基礎上開發是比較簡單的,可是這也有不少很差的地方,好比說,別人找到audio元素,而後加一個controls屬性,就能夠下載音樂了。

真正強大的是Audio API,W3C提供了操做音頻的一系列api 能夠實現更好的音頻buffer 播放效果,甚至經過analyser分析音頻進行mix混音以及音樂效果的改變。

還能夠寫好玩的動畫效果,好比

 這些的前提固然是須要對音樂有必定的瞭解,有興趣的小夥伴能夠研究一下哦,這是頗有趣的一個方向。

相關文章
相關標籤/搜索