1. 程式人生 > >H5音訊樣式修改,拖拽、點選進度操作、總時長載入

H5音訊樣式修改,拖拽、點選進度操作、總時長載入

<audio/>標籤樣式修改

修改原因:

不同手機展示的樣式不同,特別是IOS 和安卓區別很大,需要統一樣式。

修改後樣式:


修改理解:

1>“點選播放”和"點選暫停" 呼叫原生audio.play() 和 audio.pause()來對進度條進行操作

2>總時長載入:解析 audio.duration 來獲取總時長,會有部分瀏覽器相容問題,下面列舉部分相容方式。

3>點選跳轉進度:獲取當前的 滑鼠點選位置【e.pageX】 - 進度條.offsetLeft【相對於它的直接父元素 的 偏移量】,使用 translateX 改變 “藍色小球”的播放進度位置。

4>拖拽跳轉進度:監聽 onTouchStart 、 onTouchMove 和 onTouchEnd 

5> 目前缺點:

  A.只有點選 進度條 才能跳轉進度,建議擴大面積

  B.拖拽需要鬆手的時候才有效果

  C.部分 安卓 UC瀏覽器,不能愉快的載入時間,只能點選播放才能載入【已經做了其他的相容】

核心程式碼:

轉換音訊時長顯示

  /**
   * 工具類
   */
  //轉換音訊時長顯示
  transTime(time) {
    let duration = parseInt(time);
    let minute = parseInt(duration / 60);
    let sec = duration % 60 + '';
    let isM0 = ':';
    if (minute == 0) {
      minute = '00';
    } else if (minute < 10) {
      minute = '0' + minute;
    }
    if (sec.length == 1) {
      sec = '0' + sec;
    }
    return minute + isM0 + sec
  }


獲取視訊總長

  loadVideo() {
    let self = this;
    let audio = this.refs.audioTag;
    let duration = this.transTime(audio.duration);
    let time = duration == "NaN:NaN" ? "00:00" : duration;
    // alert(audio.duration);

    if (time == "00:00" && duration != "NaN:NaN" && !!initAudio) {
      audio.play();
      audio.pause();
      initAudio = false;

      window.setTimeout(() => {
        self.loadVideo();
      }, 300);
    }

    this.setState({
      voiceDuration: time,
    });
  }


更新播放進度

  timeUpdate() {
    let audio = this.refs.audioTag;
    // let value = Math.round((Math.floor(audio.currentTime) / Math.floor(audio.duration)) * 100, 0);
    // console.log("timeUpdate " + value);

    let timeline = this.refs.timeline;
    let playhead = this.refs.playhead;
    let timelineWidth = timeline.offsetWidth - playhead.offsetWidth;
    let playPercent = timelineWidth * (audio.currentTime / audio.duration);
    playhead.style.webkitTransform = "translateX(" + playPercent + "px)";
    playhead.style.transform = "translateX(" + playPercent + "px)";

    let timeCurrent = this.transTime(audio.currentTime);
    this.setState({
      timeCurrent: timeCurrent,
      currentTime: audio.currentTime,
    });
  }


進度條操作,拖拽和點選都需要呼叫

/**
   * 進度條操作
   * @param  {[type]} e [description]
   * @return {[type]}   [description]
   */
  timelineClick(e) {
    let timeline = this.refs.timeline;
    let playhead = this.refs.playhead;
    let audio = this.refs.audioTag;
    let timelineWidth = timeline.offsetWidth - playhead.offsetWidth;

    // 更新座標位置
    // e.pageX 滑鼠點選位置
    // offsetLeft  元素 相對於它的直接父元素 的 偏移量
    let newLeft = e.pageX - timeline.offsetParent.offsetLeft;
    let currentTime = audio.duration * (e.pageX - timeline.offsetParent.offsetLeft) / timelineWidth;

    if (newLeft >= 0 && newLeft <= timelineWidth) {
      playhead.style.transform = "translateX(" + newLeft + "px)";
    }
    if (newLeft < 0) {
      playhead.style.transform = "translateX(0)";
      currentTime = 0;
    }
    if (newLeft > timelineWidth) {
      playhead.style.transform = "translateX(" + timelineWidth + "px)";
      currentTime = audio.duration;
    }
    // 更新時間
    let timeCurrent = this.transTime(currentTime);
    this.setState({
      timeCurrent: timeCurrent,
      currentTime: currentTime,
    });

    // 如果在播放
    if (this.state.isPlay) {
      audio.currentTime = currentTime;
      audio.play();
    } else { // pause music
      audio.pause();
    }

  }

進度條拖拽相關

  // 進度條點選
  touchStart(e) {
    let events = e.touches[0] || e;
    this.timelineClick(events);
  }

  touchMove(e) {
    // if (this.state.touching !== true) {
    //   return;
    // }
    let events = e.touches[0] || e;
    this.timelineClick(events);
  }

  touchEnd(e) {
    this.setState({
      touching: false,
    })
  }


HTML程式碼

          <div className="inline-block voice-container">
            <audio  ref="audioTag" src={this.state.voice} onTimeUpdate={()=>this.timeUpdate()} onLoadedMetadata={()=>this.loadVideo()}/>
            <div className="controls">
              <div className="fake-control">
                <div  className="inline-block fake-control-timeline" >
                  <div ref="timeline" className="timeline inline-block" onClick={(e)=> this.timelineClick(e)} > 
                      <div ref="playhead" className="playhead" onTouchStart={(e)=>this.touchStart(e)} onTouchMove={(e)=>this.touchMove(e)} onTouchEnd={(e)=>this.touchEnd(e)}></div>
                  </div>
                  
                  <div className="inline-block play-time">
                    <div className="inline-block played-time">{this.state.timeCurrent}</div>
                    <div className="inline-block">/</div>
                    <div className="inline-block audio-time" id="audioTime">{this.state.voiceDuration}</div>
                  </div> 
                </div>
                <div className="inline-block voice-control">
                  <a className="play-pause" id="playPause" onClick={()=>this.play()}>
                    <div className="play-icon">{ this.state.isPlay ? stop : play }</div>
                  </a>
                </div>
              </div>
            </div>
            
          </div>


CSS程式碼就不具體貼上了~可以看下面的demo除錯~

踩的坑:

不能愉快的載入音訊的時長

採取相容方式:

1>第一次沒有加載出來時間的時候,自動再呼叫一次。

2>採用 播放、暫停的方式,獲取到 總時長

3>部分機型 vivo  Xplay5A等,沒有辦法在UC上的獲取到時長

相容性測試:

相容瀏覽器包括: QQ瀏覽器、微信、手淘、百度瀏覽器、UC 
相容手機包括: IPhone7, IPhone6s, 華為P8Max,小米5,OPPO R9, vivo  Xplay5A ,小米  MI5 ,魅族  note2,樂視  X900

DEMO 演示地址: