自定义音频播放组件audioPlay

本文介绍了如何实现一个自定义的音频播放组件audioPlay,功能包括播放/暂停、音量控制、播放速度调整、播放进度条以及下载。该组件基于html5的<audio>标签,利用vue进行逻辑处理。详细代码包括html、css和js部分。

一、播放器的主要功能

1、播放/暂停

2、音量控制

3、播放速度控制

4、播放进度条

5、下载

播放器如下:

二、代码实现

自定义播放器是基于html5的一个<audio>标签完成的,逻辑处理使用vue完成的。

html代码:

<Row class="audio-player" type="flex" align="middle" justify="start" :disabled="!audioFile">
    <!-- 速度控制 -->
    <Icon
      class="control-icon"
      type="ios-rewind"
      size="20"
      color="#5e72e4"
      @click="changeSpeedSlow"
    />
    <Icon
      v-show="showPlay"
      class="control-icon"
      type="ios-pause"
      size="20"
      color="#5e72e4"
      @click="handlePlay"
    />
    <Icon
      v-show="!showPlay"
      class="control-icon"
      type="ios-play"
      size="20"
      color="#5e72e4"
      @click="handlePlay"
    />
    <Icon
      class="control-icon"
      type="ios-fastforward"
      size="20"
      color="#5e72e4"
      @click="changeSpeedFast"
    />
    <span class="speed-span">X{{ multipleArray[multipleIndex] }}</span>
    <audio
      id="audioPlayer"
      ref="audio"
      preload="metadata"
      :src="audioFile"
      controlslist="nodownload"
      @loadedmetadata="onLoadedmetadata"
      @timeupdate="onTimeupdate"
      @volumechange="onVolumechange"
      @ended="onAudioEnded"
    >
      {{ $t("unsupportedTip") }}
    </audio>
    <!-- 播放进度条 -->
    <Row
      class="audio-controls"
      type="flex"
      align="middle"
      justify="space-between"
    >
      <span id="currentTime">{{ currentTime }}</span>
      <input 
        class="progress-bar" 
        ref="progressbar" 
        type="range"
        :value="sliderTime"  
        step="any" 
        min="0" 
        max="100"
        @input="handleProgress($event)"
      />
      <span id="duration">{{ duration }}</span>
    </Row>
    <!-- 音量操作 -->
    <Tooltip class="audio-mute" placement="left" theme="light">
      <Icon
        v-show="!isMute"
        class="control-icon"
        type="md-volume-up"
        size="20"
        color="#dbdbdb"
        @click.stop="handleMute"
      />
      <Icon
        v-show="isMute"
        class="control-icon"
        type="md-volume-off"
        size="20"
        color="#dbdbdb"
        @click.stop="handleMute"
      />
      <input 
        slot="content"
        class="mute-bar"
        ref="mutebar" 
        type="range"
        :value="volume"  
        step="any" 
        min="0" 
        max="100"
        @input="hancleChangeVolume($event)" 
      />
    </Tooltip>
    <!-- 下载操作 -->
    <Tooltip class="audio-download" placement="top" theme="light">
      <Icon class="control-icon" type="md-more" size="20" color="#c4c5c6" />
      <Icon
        slot="content"
        size="20"
        type="md-download"
        @click="handleDownload"
      />
    </Tooltip>
  </Row>

css代码:

.audio-player {
  .control-icon {
    margin-right: 5px;
  }
​
  .control-icon:hover {
    cursor: pointer;
  }
​
  .speed-span {
    display: inline-block;
    width: 30px;
    margin-right: 10px;
    color: #747474;
  }
​
  .audio-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 170px;
    margin-right: 5px;
​
    .progress-bar {
      width: 54%;
      height: 4px;
      cursor: pointer;
    }
​
    // 去除进度条边框
    input[type="range"]:focus {
      outline: none;
    }
​
    input[type=range]{ 
      -webkit-appearance: none;/*清除系统默认样式*/
      outline: none; 
      background: -webkit-linear-gradient(#5e72e4, #5e72e4) no-repeat, #eeeeee;  /*背景颜色,俩个颜色分别对应上下,自己尝试下就知道了嗯*/
      background-size: 0% 100%;/*设置左右宽度比例*/  
      height: 4px; /*横条的高度,细的真的比较好看嗯*/  
      border-radius: 1px;
    } 
​
    /*拖动块的样式*/ 
    input[type=range]::-webkit-slider-thumb {  
      -webkit-appearance: none;/*清除系统默认样式*/  
      width: 10px;
      height: 10px; 
      background: #5e72e4;/*拖动块背景*/ 
      border-radius: 50%; /*外观设置为圆形*/ 
    }
​
    input[type=range]::-webkit-slider-thumb:hover {
      -webkit-appearance: none;
      border: 6px solid #5e72e4; /*设置边框*/ 
    }
​
    input[type=range]::-moz-range-thumb {
      width: 8px;
      height: 8px; 
      background: #5e72e4;/*拖动块背景*/ 
      border-radius: 50%; /*外观设置为圆形*/ 
      color: transparent; //去除内阴影
      border-color: transparent; //去除原有边框
    }
​
    input[type=range]::-moz-range-thumb:hover {
      -webkit-appearance: none;
      border: 2px solid #5e72e4; /*设置边框*/ 
    }
  }
​
  .audio-mute {
    .ivu-tooltip-inner {
      width: 80px;
      display: flex;
      align-items: center;
    }
​
    .mute-bar {
      width: 100%;
      background-color: #e5e7e8;
      height: 4px;
      cursor: pointer;
    }
​
    // 去除进度条边框
    input[type="range"]:focus {
      outline: none;
    }
​
    input[type=range]{ 
      -webkit-appearance: none;/*清除系统默认样式*/
      outline: none; 
      background: linear-gradient(#545555, #545555) no-repeat, #eeeeee;  /*背景颜色,俩个颜色分别对应上下,自己尝试下就知道了嗯*/
      background-size: 0% 100%;/*设置左右宽度比例*/  
      height: 4px; /*横条的高度,细的真的比较好看嗯*/  
      border-radius: 1px;
    } 
​
    /*拖动块的样式*/
    input[type=range]::-webkit-slider-thumb {  
      -webkit-appearance: none;/*清除系统默认样式*/  
      width: 10px;
      height: 10px; 
      background: #545555;/*拖动块背景*/ 
      border-radius: 50%; /*外观设置为圆形*/ 
    }
​
    input[type=range]::-webkit-slider-thumb:hover {
      -webkit-appearance: none;
      border: 6px solid #545555; /*设置边框*/ 
    }
​
    input[type=range]::-moz-range-thumb {
      -webkit-appearance: none;/*清除系统默认样式*/  
      width: 8px;
      height: 8px; 
      background: #545555;/*拖动块背景*/ 
      border-radius: 50%; /*外观设置为圆形*/
      color: transparent; //去除内阴影
      border-color: transparent; //去除原有边框
    }
    
    input[type=range]::-moz-range-thumb:hover {
      -webkit-appearance: none;
      border: 2px solid #545555; /*设置边框*/ 
    }
  }
​
  .audio-download {
    .ivu-tooltip-arrow {
      display: none;
    }
​
    .ivu-icon-md-download:hover {
      cursor: pointer;
    }
  }
}

js代码:

export default {
  name: "audio-play",
  props: {
    audioFile: String,
  },
  data() {
    return {
      audioAllDuration: 0, //音频总播放秒数
      multipleArray: [0.5, 0.75, 1, 1.25, 1.5, 2, 3],
      multipleIndex: 2,
      timer: "",
      showPlay: false,
      currentTime: "00:00",
      duration: "00:00",
      isMute: false,
      sliderTime: 0,
      volume: 0,
    };
  },
  computed: {
  },
  methods: {
    init() {},
    //设置慢速播放播放
    changeSpeedSlow() {
      if (this.multipleIndex > 0) {
        this.multipleIndex--;
      } else {
        this.multipleIndex = 0;
      }
      this.$refs.audio.playbackRate = this.multipleArray[this.multipleIndex];
    },
    handlePlay() {
      if(!this.audioFile){
        return;
      }
      if (this.$refs.audio.paused) {
        // 开始
        this.showPlay = true;
        this.$refs.audio.play();
      } else {
        // 暂停
        this.showPlay = false;
        this.$refs.audio.pause();
      }
    },
    changeSpeedFast() {
      if (this.multipleIndex < this.multipleArray.length - 1) {
        this.multipleIndex++;
      } else {
        this.multipleIndex = this.multipleArray.length - 1;
      }
      this.$refs.audio.playbackRate = this.multipleArray[this.multipleIndex];
    },
    onLoadedmetadata(res) {
      this.duration = util.formatSeconds(res.target.duration);
      this.volume = res.target.volume * 100;
      this.isMute = res.target.muted;
      this.$refs.mutebar.style.backgroundSize = `${res.target.volume *100}% 100%`; 
    },
    // 当timeupdate事件大概每秒一次,用来更新音频流的当前播放时间
    onTimeupdate(res) {
      this.updateProgress();
    },
    onVolumechange(res) { 
      this.$refs.audio.muted = !Boolean(res.target.volume);
      this.isMute = !Boolean(res.target.volume);
    },
    handleProgress(e) {
      let rate = e.target.value / 100;
      this.$refs.audio.currentTime = this.$refs.audio.duration * rate;
      this.updateProgress();
    },    
    //更新进度条
    updateProgress() {      
      this.sliderTime = this.$refs.audio.currentTime / this.$refs.audio.duration * 100 || 0;
      this.currentTime = util.formatSeconds(this.$refs.audio.currentTime);
      this.$refs.progressbar.style.backgroundSize = `${this.sliderTime}% 100%`;
    },
    //音量操作
    hancleChangeVolume(e) {
      if(!this.audioFile){
        return;
      }
      this.volume = e.target.value;
      let _volume = e.target.value / 100; 
      this.$refs.audio.volume = _volume; 
      this.$refs.mutebar.style.backgroundSize = `${e.target.value}% 100%`;
    },
    //静音
    handleMute() {
      if (this.$refs.audio.muted) {
        //取消静音
        this.isMute = false;
        this.$refs.audio.muted = false;
      } else {
        //静音
        this.isMute = true;
        this.$refs.audio.muted = true;
      }
    },
    //下载
    handleDownload() {
      if(!this.audioFile){        
        return;
      }
      const filedir = this.audioFile && this.audioFile.split("/");
      let filename = filedir.length > 0 && filedir[filedir.length - 1] || "";     
      this.downloadVoice(this.audioFile, filename);
    },
    //下载文件流
    downloadVoice(url, fileName) {
      const a = document.createElement("a");
      a.href = url; // 文件流生成的url
      a.download = fileName; // 文件名
      (document.body || document.documentElement).appendChild(a);
      a.click();
      a.remove();
    },
    //播放完成
    onAudioEnded() {
      this.sliderTime = 0;
      this.currentTime = "00:00";
      this.showPlay = false;
      this.$refs.progressbar.style.backgroundSize = "0% 100%";
    },
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    clearTimeout(this.timer);
  },
};

1、通过从父组件传入audioFile,获取音频文件。

2、util.formatSeconds用于转换时间转为hh:dd:ss 格式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值