此音频组件具备功能如下:

  1. 音频的暂停、播放
  2. 音频支持进度条拖动播放
  3. 音频组件中有两个参数start、end时间参数(单位毫秒),用于在进度条上标记
  4. 音频实时播放时间显示、进度条显示

效果图如下:

 具体实现如下:

  1. 定义音频播放子组件(文末有下载地址)
  2. 父组件引用子组件
  3. 父组件给子组件传递参数(id、url、start、end)
    1. id:唯一标识(用于子组件中标签的动态赋值,防止多个音频之间数据污染)
    2. url:音频播放地址
    3. start:标记开始时间
    4. end:标记结束时间

废话少说

父组件:

<template>
  <el-table :data="tableData"
            stripe
            style="width: 100%">
    <el-table-column prop="date"
                     label="日期"
                     width="280">
    </el-table-column>
    <el-table-column prop="name"
                     label="姓名"
                     width="280">
    </el-table-column>

    <el-table-column label="音频预览播放"
                     min-width="150%"
                     key="audio + '{{scope.row.id}}'"
                     show-overflow-tooltip>
      <template slot-scope="scope">
        <Audio :id="scope.row.id"
               :url="scope.row.url"
               :start="scope.row.start"
               :end="scope.row.end" />
      </template>
    </el-table-column>

  </el-table>
</template>

<script>
import Audio from '../components/audio.vue'

export default {
  components: {
    Audio,
  },
  data() {
    return {
      tableData: [
        {
          id: 1,
          date: '2016-05-04',
          name: '王小虎',
          start: 20000,
          end: 59999,
          url: 'https://gu-sycdn.kuwo.cn/263856dc61e4e52add703a804afeb59d/613ac70d/resource/n2/10/14/563972959.mp3',
        },
        {
          id: 2,
          start: 120000,
          end: 180000,
          date: '2016-01-04',
          name: '王二',
          url: 'http://antiserver.kuwo.cn/anti.s?useless=/resource/&format=mp3&rid=MUSIC_96409423&response=res&type=convert_url&',
        },
      ],
    }
  },
}
</script>

子组件:

<template>
  <div class="retrievalBox_child">
    <div class="box-card">
      <!-- 列表项 -->
      <div class="retrilist">
        <div class="retridome">
          <!-- 进度条 -->
          <div class="trtricon">
            <audio id="ado"
                   controls
                   :ref="'audioItem' + id"
                   @canplay="getDuration"
                   @timeupdate="updateTime"
                   @ended="audioEnd"
                   style="display:none;">
              <source :src="filePath"
                      type="audio/ogg" />
              您的浏览器不支持 audio 元素。
            </audio>
            <!-- 播放按钮 -->
            <div class="btn"
                 :class="playing ? 'btn1' : 'btn2'"
                 @click="play"></div>
            <!-- 进度条 -->
            <div class="progress">
              <div class="huakuai"
                   :ref="'huakuaiparent' + id"
                   :style="{left:huakuaiLeft}"></div>
              <div class="fill"
                   :ref="'fill' + id"></div>
              <div class="cruxnode"
                   ref="cruxnodeparent"
                   :style="{width:cruxWidth,left:cruxLeft}"></div>
            </div>
            <!-- 时间 -->
            <div class="jindu_time">
              <span :class="'currentTime' + id">{{musicTime}}</span> /
              <span :class="'duraTime' + id">{{allTime}}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { transTime } from '../utils/tools'
export default {
  props: ['id', 'url', 'start', 'end'],
  data() {
    return {
      filePath: this.url,
      startPoint: this.start,
      endPoint: this.end,
      caseTypeList: [], //案件类型
      caseType: '',
      currentPage: 1,
      playing: true,
      musicTime: '00:00',
      allTime: '00:00',
      cruxWidth: '4px',
      cruxLeft: '0px',
      huakuaiLeft: '0%',
    }
  },
  watch: {},
  created() {},
  methods: {
    // 点击播放和暂停音频
    play() {
      this.playing = !this.playing
      if (this.playing) {
        this.$refs[`audioItem${this.id}`].pause()
      } else {
        this.$refs[`audioItem${this.id}`].play()
      }
    },
    //播放结束 修改播放状态
    audioEnd() {
      this.playing = true
      var huakuai = this.$refs[`huakuaiparent${this.id}`]
      var fill = this.$refs[`fill${this.id}`]
      huakuai.style.left = '0%'
      fill.style.width = '0%'
      var currentTime = document.querySelector('.currentTime' + this.id)
      currentTime.innerHTML = '00:00'
    },
    // 获取文件总时长
    getDuration() {
      this.allTime = transTime(this.$refs[`audioItem${this.id}`].duration)
      this.nodered()
    },
    // 小红点的位置
    nodered() {
      var cruxnode = document.querySelector('.cruxnode')
      //音频总时长
      var allduration = this.$refs[`audioItem${this.id}`].duration
      console.log(this.$refs.cruxnodeparent.offsetParent.offsetWidth)
      //音频进度条总长度
      var allWidth = this.$refs.cruxnodeparent.offsetParent.offsetWidth
      //获取音频标红区域占总长度的像素
      var qjWidth = Math.ceil(
        ((this.endPoint / 1000 - this.startPoint / 1000) / allduration) *
          allWidth
      )
      //标红起始点的像素
      var startWidth = Math.ceil(
        (this.startPoint / 1000 / allduration) * allWidth
      )
      this.cruxWidth = qjWidth + 'px'
      this.cruxLeft = startWidth + 'px'
    },
    // 实时播放时间
    updateTime() {
      let duration1 = this.$refs[`audioItem${this.id}`].duration
      this.musicTime = transTime(this.$refs[`audioItem${this.id}`].currentTime)
      // 实时播放进度条
      var huakuai = this.$refs[`huakuaiparent${this.id}`]
      var fill = this.$refs[`fill${this.id}`]
      var l =
        (this.$refs[`audioItem${this.id}`].currentTime /
          this.$refs[`audioItem${this.id}`].duration) *
        100
      this.huakuaiLeft = l + '%'
      fill.style.width = l + '%'
      if (this.musicTime == 0) {
        this.huakuaiLeft = '0%'
      }
      var currentTime = document.querySelector('.currentTime' + this.id)
      currentTime.innerHTML = this.musicTime
      var duraTime = document.querySelector('.duraTime' + this.id)
      duraTime.innerHTML = this.allTime

      var progress = document.querySelector('.progress')
      // 点击进度条
      progress.onmousedown = function (e) {
        var rate =
          ((e.clientX - progress.offsetLeft) / this.clientWidth) * this.allTime
        this.musicTime = rate - progress.clientWidth * 0.005
      }
      //进度条拖动
      let that = this
      huakuai.onmousedown = function (e) {
        var x = e.clientX - this.offsetLeft
        document.onmousemove = function (e) {
          var jlx = ((e.clientX - x) / progress.clientWidth) * 100
          if (jlx <= 100 && jlx >= 0) {
            this.huakuaiLeft = jlx + '%'
            fill.style.width = jlx + '%'
            that.$refs[`audioItem${that.id}`].currentTime =
              (jlx / 100) * duration1
          }
        }
        document.onmouseup = function (e) {
          document.onmousemove = null
          document.onmouseup = null
        }
      }
      huakuai.ontouchstart = function (e) {
        var x = e.targetTouches[0].clientX - this.offsetLeft
        document.ontouchmove = function (e) {
          var jlx =
            ((e.targetTouches[0].clientX - x) / progress.clientWidth) * 100
          if (jlx <= 100 && jlx >= 0) {
            this.huakuaiLeft = jlx + '%'
          }
          this.musicTime = (jlx / 100) * this.allTime
        }
        document.ontouchend = function (e) {
          document.ontouchmove = null
          document.ontouchend = null
        }
      }
    },
  },
}
</script>

<style lang="less" scoped>
.retrievalBox_child {
  width: 100%;
  .box-card {
    .clearfix {
      padding: 15px 30px;
      text-align: left;
      .card_top {
        width: 180px;
        /deep/.el-input__inner {
          height: 32px;
          border-radius: 4px;
          color: #939eae;
        }
        .el-icon-arrow-up:before {
          content: '\e78f';
        }
        /deep/.el-input__icon {
          line-height: 32px;
        }
      }
      .left_card {
        margin-left: 10px;
      }
    }
    .retrilist {
      overflow-y: hidden;
      .retridome {
        width: 96%;
        // height: 140px;
        border: 1px solid #e7eaef;
        margin: 0 auto;
        .trtrititle {
          width: 98%;
          height: 30px;
          margin: 0 auto;
          position: relative;
          .title_img {
            display: inline-block;
            position: absolute;
            top: 7px;
            width: 16px;
            height: 16px;
            background: url(../assets/images/yinpinpianduan.png) no-repeat;
            background-size: 100% 100%;
          }
          .title_txt {
            height: 30px;
            line-height: 30px;
            position: absolute;
            display: inline-block;
            left: 22px;
            font-size: 12px;
          }
        }
        .trtricon {
          width: 95%;
          height: 38px;
          margin: 0 auto;
          position: relative;
          //   background-color: #f1f1f1;
          .btn {
            width: 12px;
            height: 12px;
            position: absolute;
            left: -5px;
            top: 14px;
          }
          .btn1 {
            background: url(../assets/images/bofang.png) no-repeat;
            background-size: 100% 100%;
          }
          .btn2 {
            background: url(../assets/images/zanting.png) no-repeat;
            background-size: 100% 100%;
          }
          .progress {
            width: 70%;
            height: 4px;
            background-color: #e1e1e1;
            position: absolute;
            top: 48%;
            left: 2%;
            .huakuai {
              position: absolute;
              top: -0.2rem;
              width: 20px;
              height: 10px;
              background: url(../assets/images/huakuai.png) no-repeat;
              background-size: 100% 100%;
              z-index: 9;
            }
            .fill {
              position: absolute;
              top: 0;
              height: 4px;
              background-color: #3299cc;
            }
            .cruxnode {
              position: absolute;
              top: 0;
              // right: 10%;
              width: 4px;
              height: 4px;
              background-color: red;
              //   z-index: 10;
              //   border-radius: 100%;
            }
          }
          .jindu_time {
            position: absolute;
            top: 20%;
            right: 3%;
            font-size: 12px;
            color: #666666;
          }
        }
        .trtribom {
          width: 98%;
          height: 50px;
          margin: 10px auto;
          .bom {
            float: left;
            width: 100px;
            height: 100%;
            margin-right: 100px;
            span {
              display: inline-block;
              width: 100%;
              font-size: 12px;
              text-align: center;
            }
            .bom_bottom {
              padding-top: 15px;
            }
          }
        }
      }
    }
  }
}
</style>

demo项目下载地址:

https://download.csdn.net/download/feilong806/22618071https://download.csdn.net/download/feilong806/22618071

demo中已删除引入的包,下载后自行npm 

Logo

前往低代码交流专区

更多推荐