1

前言

image.png

一开始看到UI设计稿,我内心是十分抗拒的。觉得用原生audio的样式就可以了,也不是特别丑,毕竟时间给的不多,自定义样式还要改逻辑啥的。在网上搜索了一番有没有合适的插件,没有看到心动的。最后还是硬着头皮自己写了。

参考了一个博客,很感谢这位博主,逻辑都可以用。不过原博用的jquery,我自己用vue,而且我的页面可能有不止一个audio,设计稿和原博也很不一样,所以改代码还是花了一番心思。

参考链接: 音频(audio)自定义样式以及控制操作面板
vue版本:2.6.12

我这里是按照我的设计稿做出来的样子,如果你的设计稿跟我的不一样,那也只需要改一下css部分和html,js还是能直接套用的。

如果急用的同学可以直接跳到最后看完整的代码,复制了不出意外可以直接用的,只需要把播放按钮的图片改成你自己的图片,再添加可用的audio链接就可以了。

html代码:

<div class="page-container">
    <div v-for="(item, index) in content" :key="index" class="list-box">
      <audio ref="audio" :src="item.audio_url" controls @loadedmetadata="fillTime($event, index)"
        @timeupdate.stop="updateProgress(index)" @ended.stop="audioEnded(index)">
      </audio>
      <!-- 音频名字 -->
      <div class="audio-name">{{ item.audio_name }}</div>
      <div class="control-row">
        <!-- 控制播放暂停的按钮 -->
        <img src="@/assets/play.png" class="play-icon" alt="" @click="playAudio(index)">
        <div class="row-right">
          <!-- 进度条 -->
          <div class="pgs">
            <div class="pgs-play"></div>
          </div>
          <!-- 当前播放时长和总时长 -->
          <div class="time-row">
            <span class="played-time">{{ audioArr[index].currentTime }}</span>
            <span class="audio-time">{{ audioArr[index].duration }}</span>
          </div>
        </div>
      </div>
    </div>
  </div>

js代码:

export default {
    data() {
      return {
        audioNodes: [],    // 用于存放所有 audio 的 DOM 节点
        audioArr: [],       // 用于维护 audio 的总时长和当前播放时间的数组
        content: [           // 存放audio的地址信息,一般是接口返回
            {"audio_name":"20210112_1056.m4a","audio_url":"https://xxx.com/android1610420451567524.m4a"},
            {"audio_name":"20210112_1056.m4a","audio_url":"https://xxx.com/android1610420451567524.m4a"},
        ]
      }
    },
    mounted() {
      this.audioNodes = document.getElementsByClassName('list-box')
      this.content.forEach((item, index) => {
        this.$set(this.audioArr, index, { duration: '', currentTime: '00:00' })
      })
    },
    methods: {
      // 切换播放,暂停按钮的事件
      playAudio(index) {
        let audio = this.audioNodes[index].firstChild
        if (audio.paused) {
          audio.play()
        } else {
          audio.pause()
        }
      },
      
      // 获取音频的总时长
      fillTime(event, index) {
        this.audioArr[index].duration = this.transTime(event.target.duration)
      },

      // 将秒数转化成(分:秒)格式
      transTime(time) {
        let duration = parseInt(time)
        let minute = parseInt(duration / 60).toString().padStart(2, '0')
        let sec = (duration % 60).toString().padStart(2, '0')
        return `${minute}:${sec}`
      },

      // 进度条播放的事件
      updateProgress(index) {
        let audio = this.audioNodes[index].firstChild
        let value = Math.round((Math.floor(audio.currentTime) / Math.floor(audio.duration)) * 100, 0)
        this.audioArr[index].currentTime = this.transTime(audio.currentTime)
        let progressTag = this.audioNodes[index].getElementsByClassName('pgs-play')[0]
        progressTag.style.left = `${value}%`
      },

      // 播放结束的处理动作
      audioEnded(index) {
        let audio = this.audioNodes[index].firstChild
        audio.currentTime = 0
        audio.pause()
      },
    }
  }

css代码:

.pgs {
      background-color: #D8D4D1;
      text-align: center;
      position: relative;
      height: 2px;
      margin-bottom: 10px;
    }

    .pgs-play {
      position: absolute;
      top: -2.5px;
      left: 0;
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background-color: #B03F28;
      z-index: 1;
    }

    .play-icon {
      width: 45px;
      height: 45px;
      margin-right: 15px;
    }
    audio {
      display: block;
      height: 0;
    }
    .audio-box {
      background: #F5F5F5;
      border: 1px solid #D8D4D1;
      border-radius: 5px;
      width: 100%;
      padding: 15px 12px;
      box-sizing: border-box;
    }
    .audio-name {
      font-size: 15px;
      color: #252120;
      margin-bottom: 15px;
      overflow:hidden; //超出的文本隐藏
      text-overflow:ellipsis; //溢出用省略号显示
      white-space:nowrap; //溢出不换行
    }
    .control-row {
      display: flex;
      align-items: flex-end;
    }
    .row-right {
      flex-grow: 100;
    }
    .time-row {
      position: relative;
      color: #B0AFAD;
      font-size: 12px;
      margin-bottom: 3px;
    }
    .audio-time {
      position: absolute;
      right: 0;
    }

完整代码(audio.vue)

  • 可以直接套用,只需要改control-row里面的图片地址,这是播放按钮的图片。
<style lang="scss">
  .page-container {
    .pgs {
      background-color: #D8D4D1;
      text-align: center;
      position: relative;
      height: 2px;
      margin-bottom: 10px;
    }

    .pgs-play {
      position: absolute;
      top: -2.5px;
      left: 0;
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background-color: #B03F28;
      z-index: 1;
    }

    .play-icon {
      width: 45px;
      height: 45px;
      margin-right: 15px;
    }

    audio {
      display: block;
      height: 0;
    }

    .audio-box {
      background: #F5F5F5;
      border: 1px solid #D8D4D1;
      border-radius: 5px;
      width: 100%;
      padding: 15px 12px;
      box-sizing: border-box;
    }

    .audio-name {
      font-size: 15px;
      color: #252120;
      margin-bottom: 15px;
      overflow: hidden; //超出的文本隐藏
      text-overflow: ellipsis; //溢出用省略号显示
      white-space: nowrap; //溢出不换行
    }

    .control-row {
      display: flex;
      align-items: flex-end;
    }

    .row-right {
      flex-grow: 100;
    }

    .time-row {
      position: relative;
      color: #B0AFAD;
      font-size: 12px;
      margin-bottom: 3px;
    }

    .audio-time {
      position: absolute;
      right: 0;
    }
  }
</style>

<template>
  <div class="page-container">
    <div v-for="(item, index) in content" :key="index" class="list-box">
      <audio ref="audio" :src="item.audio_url" controls @loadedmetadata="fillTime($event, index)"
        @timeupdate.stop="updateProgress(index)" @ended.stop="audioEnded(index)">
      </audio>
      <!-- 音频名字 -->
      <div class="audio-name">{{ item.audio_name }}</div>
      <div class="control-row">
        <!-- 控制播放暂停的按钮 -->
        <img src="@/assets/play.png" class="play-icon" alt="" @click="playAudio(index)">
        <div class="row-right">
          <!-- 进度条 -->
          <div class="pgs">
            <div class="pgs-play"></div>
          </div>
          <!-- 当前播放时长和总时长 -->
          <div class="time-row">
            <span class="played-time">{{ audioArr[index].currentTime }}</span>
            <span class="audio-time">{{ audioArr[index].duration }}</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        audioNodes: [],    // 用于存放所有 audio 的 DOM 节点
        audioArr: [],       // 用于维护 audio 的总时长和当前播放时间的数组
        content: [           // 存放audio的地址信息,一般是接口返回
            {"audio_name":"20210112_1056.m4a","audio_url":"https://xxx.com/android1610420451567524.m4a"},
            {"audio_name":"20210112_1056.m4a","audio_url":"https://xxx.com/android1610420451567524.m4a"},
        ]
      }
    },
    mounted() {
      this.audioNodes = document.getElementsByClassName('list-box')
      this.content.forEach((item, index) => {
        this.$set(this.audioArr, index, { duration: '', currentTime: '00:00' })
      })
    },
    methods: {
      // 切换播放,暂停按钮的事件
      playAudio(index) {
        let audio = this.audioNodes[index].firstChild
        if (audio.paused) {
          audio.play()
        } else {
          audio.pause()
        }
      },
      
      // 获取音频的总时长
      fillTime(event, index) {
        this.audioArr[index].duration = this.transTime(event.target.duration)
      },

      // 将秒数转化成(分:秒)格式
      transTime(time) {
        let duration = parseInt(time)
        let minute = parseInt(duration / 60).toString().padStart(2, '0')
        let sec = (duration % 60).toString().padStart(2, '0')
        return `${minute}:${sec}`
      },

      // 进度条播放的事件
      updateProgress(index) {
        let audio = this.audioNodes[index].firstChild
        let value = Math.round((Math.floor(audio.currentTime) / Math.floor(audio.duration)) * 100, 0)
        this.audioArr[index].currentTime = this.transTime(audio.currentTime)
        let progressTag = this.audioNodes[index].getElementsByClassName('pgs-play')[0]
        progressTag.style.left = `${value}%`
      },

      // 播放结束的处理动作
      audioEnded(index) {
        let audio = this.audioNodes[index].firstChild
        audio.currentTime = 0
        audio.pause()
      },
    }
  }
</script>

文章到这里就结束了,如果对你有帮助,欢迎点赞,收藏,谢谢~


DDD7
265 声望5 粉丝

幻想某一天顶替产品经理的前端妹砸(>V