不想用radio的样式?来自定义一个音乐播放器

267 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情

自定义音乐播放器

先看效果:

01.png

这里的话需要先引入element-plus,因为里面需要用到一个快进弹出框

播放器

需要用到的设置

const speedVisible = ref<boolean>(false); // 设置音频播放速度弹窗
const audioRef = ref(); // 音频标签对象
const activeSpeed = ref(1); // 音频播放速度
const audioDuration = ref(0); // 音频总时长
const audioCurrent = ref(0); // 音频当前播放时间
const audioVolume = ref(1); // 音频声音,范围 0-1
const playStatus = ref<boolean>(false); // 音频播放状态:true 播放,false 暂停
const playProgress = ref(0); // 音频播放进度
const timeInterval = ref(); // 获取音频播放进度定时器

首先需要两张图片一个暂停一个开始

这里的话需要用定位将两张图片重叠起来

<img src="../assets/image/start.png" alt="" class="play-icon" />
<img src="../assets/image/stop.png" alt="" class="play-icon" />

其次需要准备音乐时间的展示数字,进度条,声音以及设置的音乐倍数

<!-- 时间展示 -->
<span class="play-time">
    {{ transTime(audioCurrent) }}/{{ transTime(audioDuration) }}
</span>
<!-- 进度条 -->
<div class="play-progress">
    <div class="play-current-progress" :style="{ width: `${playProgress}%` }"></div>
</div>
<!-- 音量和静音图标 -->
<img src="../assets/image/bofang.png" alt="" class="play-voice" v-if="audioVolume === 1" @click="onSetVolume(0)" />
<img src="../assets/image/jingy.png" alt="" class="play-voice" v-else @click="onSetVolume(1)" />
<!-- 倍数弹窗 -->
<el-popover v-model:visible="speedVisible" placement="top" :width="50">
    <div v-for="item in speedList" :key="item.value" @click="onChangeSpeed(item.value)" style="margin-bottom: 17px; cursor: pointer; text-align: center">
        <span>{{ item.label }}</span>
    </div>
    <template #reference>
        <span class="play-speed" @click="onHandleSpeed">{{ activeSpeed }}x</span>
    </template>
</el-popover>
<!-- 音频 -->
<audio ref="audioRef" :src="musicSource" @canplay="onCanplay"></audio>

样式部分:

:deep(.van-nav-bar) {
  background-color: transparent !important;
}

.audio-player {
  width: 90%;
  height: 52px;
  background: linear-gradient(180deg, #505572 0%, #383b4f 100%);
  border-radius: 8px;
  padding: 9px 11px;
  margin: 0 auto;
  box-sizing: border-box;
  display: flex;
  align-items: center;

  .play-icon {
    width: 34px;
    height: 34px;
    margin-right: 7px;
    cursor: pointer;
  }

  .play-time {
    width: 72px;
    color: #35bda5;
    font-size: 14px;
    display: inline-block;
    margin-right: 16px;
  }

  .play-progress {
    width: 160px;
    height: 4px;
    background-color: #323547;
    box-shadow: inset 0px 1px 0px 0px #20222d;
    border-radius: 2px;
    margin-right: 16px;
    position: relative;
    .play-current-progress {
      height: 4px;
      background: #2385bf;
      border-radius: 2px;
      position: absolute;
      top: 0;
      left: 0;
    }
  }

  .play-voice {
    width: 20px;
    height: 20px;
    margin-right: 14px;
    cursor: pointer;
  }

  .play-speed {
    cursor: pointer;
    color: #35bda5;
    font-size: 16px;
  }
}
:deep(.van-nav-bar__text) {
  color: #000;
}

将音乐先弄出来

 <audio ref="audioRef" :src="musicSource" @canplay="onCanplay"></audio>
const musicSource: any = ref(null);
const wenan = ref("");
const sing = ref("");
const Picture = ref("");
onMounted(()=>{
      axios.get("音乐接口").then((res) => {
        console.log(res);
        musicSource.value = res.data.music;
        console.log(musicSource.value);
        wenan.value = res.data.singer;
        sing.value = res.data.name;
        Picture.value = res.data.Picture;
    })
    .catch((error) => {})
    .finally(() => {
      status.loading = false;
    });
})

const onPlay = async () => {
  // 音频播放完后,重新播放
  if (playProgress.value === 100) audioRef.value.currentTime = 0;

  await audioRef.value.play();
  playStatus.value = true;
  audioDuration.value = audioRef.value.duration;

  timeInterval.value = setInterval(() => {
    audioCurrent.value = audioRef.value.currentTime;
    playProgress.value = (audioCurrent.value / audioDuration.value) * 100;
    if (playProgress.value === 100) onPause();
  }, 100);
};
const onPause = () => {
  audioRef.value.pause();
  playStatus.value = false;
  /* 用完释放定时器 */
  clearInterval(timeInterval.value);
};

清除定时器

onBeforeMount(() => {
  clearInterval(timeInterval.value);
});

设置倍数 需要一个数组来存放显示的倍数以及他绑定的值

const speedList = [
  {
    label: "2x",
    value: 2,
  },
  {
    label: "1.5x",
    value: 1.5,
  },
  {
    label: "1x",
    value: 1,
  },
  {
    label: "0.75x",
    value: 0.75,
  },
];
const onChangeSpeed = (value: number) => {
  activeSpeed.value = value;
  // 设置倍速
  audioRef.value.playbackRate = value;
  speedVisible.value = false;
};
const onHandleSpeed = () => {
  speedVisible.value = !speedVisible.value;
};

设置声音

// 设置声音
const onSetVolume = (value: number) => {
  audioRef.value.volume = value;
  audioVolume.value = value;
};

播放时间换算

// 音频播放时间换算
const transTime = (value: number) => {
  let time = "";
  let h = parseInt(String(value / 3600));
  value %= 3600;
  let m = parseInt(String(value / 60));
  let s = parseInt(String(value % 60));
  if (h > 0) {
    time = formatTime(h + ":" + m + ":" + s);
  } else {
    time = formatTime(m + ":" + s);
  }
  return time;
};

格式化时间显示,补全对其

// 格式化时间显示,补零对齐
const formatTime = (value: string) => {
  let time = "";
  let s = value.split(":");
  let i = 0;
  for (; i < s.length - 1; i++) {
    time += s[i].length == 1 ? "0" + s[i] : s[i];
    time += ":";
  }
  time += s[i].length == 1 ? "0" + s[i] : s[i];

  return time;
};

到这里播放器就做好了,接下来就是将接口的图片以及歌手歌曲名称渲染在盒子里排一下版就可以了。

<div style="display: flex;justify-content: space-around;align-items: center;margin-bottom: 5px;">
    <div style="width: 50%;5px;height: 100px;text-align: center;">
        <van-image round width="100px" height="100px" :src="Picture" />
    </div>
    <p style="font-family:FMXRDMH;display: flex;flex-wrap: wrap;font-size: 18px;"><span> 歌手:{{wenan}}</span><span> 歌曲:{{sing}}</span></p>
</div>