音乐播放器

492 阅读3分钟

       html提供的audio标签样子太固定,大部分时候我们需要自定义播放器的样式。之前没事的时候写过一个,但是只是实现了功能,没有完善。项目上用了一个大神的插件,由于没有提供源码,部分功能没法通过api实现,正好趁这个机会总结一下。

      我们常用的功能无非就是播放、暂停,快进快退、音量控制,播放进度条。这里我们需要获取音频播放总时间、缓存时间、已播放时间以及音量获取设置。

使用到的方法属性如下:

  1. readyState :音频加载状态,比如 0 未完成,4完成,我们所有对它的操作都应该在4以后。
  2. pause() : 暂停
  3. play() : 播放
  4. paused : 是否暂停
  5. duration : 播放总时间
  6. currentTime : 已经播放的时间,这个属性可以赋值,赋值就是定位到那个时间,我们快进快退时候使用它就好
  7. 缓存时间获取:首先获取已缓冲部分的 TimeRanges 对象:var timeRanges = this.mp3.buffered;然后通过timeRanges.end(timeRanges.length - 1)获取缓存时间

  8. volume : 音量获取设置,值在0到1之间,设置值就是调节音量大小。

具体代码

js部分(暂时没做音量控制)

import React from 'react';
import styles from './index.module.scss';
import { Progress } from 'antd';

class Mp3 extends React.Component {
    constructor(){
        super();
        this.state = {
            isPlay: false,
            duration : 0,            // 总时间
            timeBuffered : 0,        // 缓存时间
            currentTime : 0,         // 当前播放时间
        }
    }

    goBack = () => {
        if(this.mp3.readyState !== 4) return;
        this.currentTime -= this.props.step || 15;
        this.setState({currentTime : this.mp3.currentTime});
    }

    fastForward = () => {
        if (this.mp3.readyState !== 4) return;
        this.mp3.currentTime += this.props.step || 15;
        this.setState({currentTime:this.mp3.currentTime});
    }

    pause = () =>{
        if(this.mp3.readyState !== 4) return;
        if(this.mp3.paused){
            this.mp3.play();
            this.setSate({isPlay:true});    
        }else{
            this.mp3.pause();
            this.setState({isPlay:false});
        }
    }

    componentDidMount(){
        this.mp3 = document.getElementById('myAudioComponentLiu');
        // 获取缓存的时间
        this.timer = setInterval(()=>{
            if(this.mp3.readyState === 4){
                if(this.state.duration !== this.mp3.duration){
                    this.setState({duration:this.mp3.duration});
                }
                // 获取已缓存部分的 TimeRanges 对象
                var timeRanges = this.mp3.buffered;
                // 获取已缓存的时间
                var timeBuffered = timeRanges.end(timeRanges.length -1);
                if(this.state.timeBuffered !== timeBuffered){
                    this.setState({timeBuffered});
                }
                if(this.state.currentTime !== this.mp3.currentTime){
                    this.setState({currentTime:this.mp3.currentTime});
                }
            }
        },1000)
    }

    componentWillUnMount(){
        clearInterval(this.timer);
    }

    setTimes = (value)=>{
        let secondTime = parseInt(value);
        let min = 0;
        let h = 0;
        let result = '';
        if(secondTime > 60){
            min = parseInt(secondTime / 60);
            secondTime = parseInt(secondTime % 60);
            if(min > 60){
                h = parseInt(min / 60);
                min = parseInt(min % 60);
            }
        }
        if(min > 60){
            result = `${h.toString().padStart(2,"0")}:${min.toString().padStart(2,"0")}:${secondTime.toString().padStart(2,"0")}`;;
        }else{
            result = `${min.toString().padStart(2,"0")}:${secondTime.toString().padStart(2,"0")}`;
        }
        return result;
    };

    render(){
        let {duration,timeBuffered,currentTime,isPlay} = this.state;
        // 这里可以赋值两张快进快退的默认图片
        let {backImg,goImg,src} = this.props;
        return (
            <div className={styles.container}>
                <img onClick={this.goBack} className={styles.back} src = {backImg} alt=''/>
                <audio id="myAudioComponentLiu" preload="meta" src = {src} />
                <div className={styles.btnBox}>
                    <div className={isPlay?styles.pause:styles.play} onClick={this.pause}></div>
                </div>
                <Progress style ={{margin:"0 0.3rem"}} showInfo={false} percent={timeBuffered / duration *100} success={{percent:currentTime/duration *100}}/>
                <span className={styles.time}>
                    {this.setTimes(currentTime)}/{this.setTimes(duration)}
                </span>
                <img onClick={this.fastForward} className={styles.go} src={goImg} alt=""/>
            </div>
        );
    }
}

export default Mp3;

css部分

.container {  display: flex;  align-items: center;  .back,.go {    cursor: pointer;    flex-shrink: 0;    width: 50px;    user-select: none;    &:hover {      opacity: 0.8;    }  }  .back {    margin-right: 25px;  }  .go {    margin-left: 25px;  }  .btnBox {    display: flex;    justify-content: center;    align-items: center;    width: 50px;    .play {      display: inline-block;      cursor: pointer;      border-top: 25px solid transparent;      border-bottom: 25px solid transparent;      border-left: 35px solid #000;      margin: 0 13px;      &:hover{        opacity: 0.8;      }    }    .pause {      position: relative;      cursor: pointer;      width: 39px;      height: 50px;      &::before,&::after {        content: '';        position: absolute;        top: 0;        bottom: 0;        width: 13px;        background-color: #000;        border-radius: 18px;      }      &::before {        left: 0;      }      &::after {        right: 0;      }      &:hover{        opacity: 0.8;      }    }  }  .time {    color: #000;    font-size: 25px;    min-width: 214px;    text-align: center;    user-select: none;  }  :global {    .ant-progress-inner {      position: absolute;      top: 50%;      transform: translateY(-50%);      background-color: #f2f7f7;      .ant-progress-bg {        height: 15px !important;        background-color: #dfeaea;      }      .ant-progress-success-bg {        height: 15px !important;        background-color: #13bb74;      }    }  }}

使用

  1. step:number 一次快进或者快退几秒,默认是15s,非必传

  2. backImg :string:快退图片地址,非必传

  3. goImg : string:快进图片地址,非必传

  4. src :string:音频地址,必传

import Mp3 from './components/Mp3/Mp3';

// 下边使用
<Mp3 step={5} backImg={‘快退图片’} goImg={imgUrl('快进图片')} src={'音频地址'}/>

参考文章

  1. 详细音频api
  2. 样式参考react-custom-audio