Skip to content

Latest commit

 

History

History
152 lines (102 loc) · 4.45 KB

简易播放器.md

File metadata and controls

152 lines (102 loc) · 4.45 KB

摸了个简易播放器,缓冲只在播放时去做,还挺粗糙的,拖拽还没写

功能: 播放,暂停,上一首,下一首,切歌,(默认循环播放)

目录:

  1. 进度条

    (1) timeRange

  2. 播放,暂停

  3. 上一首,下一首


进度条

  1. 这里其实是三条线,音频总长,缓冲,当前播放量,三条线用绝对定位就好了,给上不同的颜色

  2. 重点在于这三个变量,当前音频总时长,缓冲了多少,以及当前播放的位置

  3. 不得不说原生的JavaScript对音频视频的支持还是很强大的,具体参考这个吧http://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp

    this.audioPlay.duration     // 返回当前音频/视频的长度(以秒计)
    this.audioPlay.currentTime  // 设置或返回音频/视频中的当前播放位置(以秒计)
    this.audioPlay.buffered     // 返回表示音频/视频已缓冲部分的 TimeRanges 对象
    
  4. 缓冲拿到的是timeRanges对象,这个当时懵了一下,稍微解释一下吧

timeRange
  1. 查询数据时指定的时间戳范围或特定时间戳值。

  2. MDN上讲的云里雾里的,然后是看了这篇,对应到缓冲上的解释挺合理的

    length - 获得音视频中已缓冲范围的数量

    start(index) - 获得某个已缓冲范围的开始位置

    end(index) - 获得某个已缓冲范围的结束位置

    index 是想要检索的时间范围的索引值,因此这里我们用end(0)

  3. 需要注意的一点是,length === 0 的情况下,说明没有缓冲,这个时候end(0)会报错,

    let buffered = this.audioPlay.buffered;
    bufferedTime = buffered.length ? buffered.end(0) : 0;
    

    基本工作做完了,之后可以开始播放了


播放,暂停

  1. 播放,暂停

    this.audioPlay.play();  // 播放
    this.audioPlay.pause(); // 暂停
    

    嗯,但这样就算完了吗?音频文件确实播放了,但是我的进度条...

  2. 我是不是该监听一下整个播放过程

    事件 => timeupdate => 当目前的播放位置已更改时
    this.audioPlay.ontimeupdate = this.listenPlay;
    
  3. 完整代码

      // 点击播放,暂停
      handleAudioPlay = () => {
        this.setState({isPlay: !this.state.isPlay})
        if ( !this.state.isPlay ) {
          this.audioPlay.play();
          this.audioPlay.ontimeupdate = this.listenPlay;
        } else {
          this.audioPlay.pause();
        }
      }
    

上一首,下一首

  1. 之前只有一首音频文件,播放完了就没了,那现在我想播放多首,

  2. 需要知道当前音频是否播放完了,然后切换到下一首

    this.audioPlay.ended;  // true/false 当目前的播放列表已结束时
    
    // 这里默认循环播放,当已经是最后一首时,下一首播放第一首,
    let idx = this.state.musicIndex === musicLists.length - 1 ? 0 
    		  : this.state.musicIndex + 1;
    
  3. 完整代码

    // 监听播放进度
    listenPlay = () => {
      this.setTimeParams();
      this.audioPlay.ended && this.handleNextPlay();
    }
    
    // 下一首
    handleNextPlay = () => {
      let idx = this.state.musicIndex === musicLists.length - 1 ? 0 
      			: this.state.musicIndex + 1;
      this.setMusicIndex(idx);
    }
    

    然后重置一下播放器,

  4. 这个时候已经出bug了,第一次获取的duration有问题,点击下一首时,显示的时间是上一首的,然后我用了setTimeout延迟了一秒,再重置,发现这样居然正确了。

  5. 继续排查,console一下this.audioPlay,发现不用setTimeout的结果是慢了,返回的是上一首

  6. 百度了一下,说用oncanplay就可以了,试了一下还真的可以,

    事件 => canplay => 当浏览器可以播放音频/视频时
    
    // 重置播放器 
    resetPlayer = () => {
      this.audioPlay.oncanplay = () => {
        let params = {
          bufferedTime: 0,
          currentTime: 0,
          duration: this.audioPlay.duration
        }
        this.setState({...params});
        this.state.isPlay ? this.audioPlay.play() : this.audioPlay.pause();
      };
    }
    

    理解一下,当前音频还没有加载进来,因此需要通过oncanplay监听一下,在 audio 元素加载完成后 ,再去获取需要的变量值,此时才能获取到正确的 duration 值

  7. 下一首,切歌,就不说了,思路是通过idx获取当前播放的歌曲是哪一首