意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

用Vue3怎样实现音乐播放器组件,要做什么准备

来源:恒创科技 编辑:恒创科技编辑部
2024-01-21 10:19:59
这篇主要是介绍“用Vue3怎样实现音乐播放器组件,要做什么准备”的内容了,下文有实例供大家参考,对大家了解操作过程或相关知识有一定的帮助,而且实用性强,希望这篇文章能帮助大家解决用Vue3怎样实现音乐播放器组件,要做什么准备的问题,下面我们一起来了解看看吧。

前言

用Vue3实现一个简易的音乐播放器组件

其效果图如下所示:


用Vue3怎样实现音乐播放器组件,要做什么准备

实现这个组件需要提前做的准备:

引入ElementUI 引入字节跳动图标库 一张唱见图片 将要播放的音乐上传到文件服务器上,并提供一个能在线访问的链接【这里使用的是阿里云的OSS服务】

准备

ElementUI

ElementUI的引入可以参照其官网的引入方式;

字节跳动图标库

组件的【上一首】【播放】【下一首】【音量】等图标都是来源自这个图标库,这是其安装文档

在main.js中,我是这样引入的:

//引入字节跳动图标库
import {install} from '@icon-park/vue-next/es/all';
import '@icon-park/vue-next/styles/index.css';

......

//这种加载方式进行加载的话,代表使用默认的前缀进行加载:icon
//也就是说假如要使用一个主页图标,使用图标时标签该这么写:
//<icon-home theme="outline" size="24" fill="#FFFFFF" :strokeWidth="2"/>
//install(app,'prefix') 用这种方式进行加载的话,可以自定义使用图标库时的标签前缀
install(app)

唱见图片

音乐源

将要播放的音乐放到文件服务器上,我这里是使用阿里云的OSS服务进行音乐文件的存储,然后在整个页面加载时【也就是在onMounted生命周期函数中获取这些数据源】。在后面的代码中,这一步体现在:

//初始化歌曲源
const initMusicArr = () => {
    requests.get("/Music/QueryAllMusic").then(function (res) {
      musicState.musicArr = res

      musicState.musicCount = res.length
    })
  }

  onMounted(() => {
    initMusicArr()

      ......
  })

完整代码

<template>

 <!--音乐播放器-->
 <div class="music-container" :class="{'music-active-switch': offsetThreshold}">
  <div class="music-disk">
   <!--唱片图片-->
   <img class="music-disk-picture" :class="{'music-disk-playing-style': playState}" src="./images/R-C.png"
     alt="">
  </div>

  <!--进度条-->
  <div class="music-slider">
   <el-slider
     v-model="playTime"
     :format-tooltip="tooltipFormat"
     size="small"
     :max="sliderLength"
     @change="changePlayTime"/>
  </div>

  <!--按钮组-->
  <div class="button-group">
   <!--上一曲 按钮-->
   <button class="play-button" @click="lastButtonClick">
    <icon-go-start theme="outline" size="23" fill="#939393" :strokeWidth="3" strokeLinejoin="miter"
           strokeLinecap="butt"/>
   </button>
   <!--播放 按钮-->
   <button class="play-button" @click="playButtonClick">
    <icon-play-one v-if="!playState" theme="outline" size="23" fill="#939393" :strokeWidth="3"
           strokeLinejoin="miter" strokeLinecap="butt"/>
    <icon-pause v-if="playState" theme="outline" size="23" fill="#939393" :strokeWidth="3"
          strokeLinejoin="miter" strokeLinecap="butt"/>
   </button>
   <!--下一曲 按钮-->
   <button class="play-button" @click="nextButtonClick">
    <icon-go-end theme="outline" size="23" fill="#939393" :strokeWidth="3" strokeLinejoin="miter"
          strokeLinecap="butt"/>
   </button>
   <!--音量按钮-->
   <div class="voice-container">
    <button class="voice-button" @click="voiceButtonClick">
     <icon-volume-notice v-if="!voiceMute" theme="outline" size="23" fill="#939393" :strokeWidth="3"
               strokeLinejoin="miter" strokeLinecap="butt"/>
     <icon-volume-mute v-if="voiceMute" theme="outline" size="23" fill="#939393" :strokeWidth="3"
              strokeLinejoin="miter" strokeLinecap="butt"/>
    </button>
    <div class="voice-slider">
     <el-slider
       v-model="voicePower"
       :max="1"
       :step="0.1"
       size="small"
       @change="changeVoicePower"/>
    </div>
   </div>
  </div>

  <audio
    ref="musicAudio"
    class="audio-component"
    controls
    preload="auto"
    @canplay="changeDuration">
   <source ref="musicSource" type="audio/mpeg"/>
  </audio>
 </div>

</template>

<script>
import {computed, onMounted, onUnmounted, reactive, ref, watch} from "vue";

//这里是自己封装的axios请求,可以将这里替换成自己的请求逻辑
import requests from "@/api/ajax";

export default {
 name: "index",
 setup() {

  //是否正在播放
  const playState = ref(false);

  //现在的播放时间
  const playTime = ref(0.00);

  //歌曲的时间长度
  const playDuration = ref(0.00);

  //进度条长度
  const sliderLength = ref(100);

  //歌曲URL
  const musicUrl = ref("");

  //播放器标签
  const musicAudio = ref(null);

  //实现音乐播放的标签
  const musicSource = ref(null);

  //是否静音
  const voiceMute = ref(false);

  //音量大小
  const voicePower = ref(0.5);

  const musicState = reactive({
   musicArr: [],
   musicCount: 0
  })

  const musicCursor = ref(0);

  //页面偏移量
  const pageOffset = ref(0)

  //是否达到阈值,达到阈值就显示播放器,反之
  const offsetThreshold = ref(false)

  //激活播放器
  const operateMusicPlayer = () => {
   pageOffset.value = window.scrollY
   //当页面滚动偏移达到800,激活用户框
   if (pageOffset.value > 800) {
    offsetThreshold.value = true
   } else {
    //反之
    offsetThreshold.value = false
   }
  }

  //播放按钮点击回调
  const playButtonClick = () => {

   if (playState.value) {
    musicAudio.value.pause()
   } else {
    musicAudio.value.play()
   }

   //修改播放时间【设置这个,当一首歌正常播放结束之后,再次点击播放按钮,进度条会得到重置】
   playTime.value = musicAudio.value.currentTime

   //重新设置播放状态
   playState.value = !playState.value
  }

  //上一曲按钮点击回调
  const lastButtonClick = () => {
   musicCursor.value -= 1

   changeMusic()
  }

  //下一曲按钮点击回调
  const nextButtonClick = () => {
   musicCursor.value += 1

   changeMusic()
  }

  //歌曲进度条文本提示
  const tooltipFormat = (val) => {

   let strTime = playTime.value

   let strMinute = parseInt(strTime / 60 + '')

   let strSecond = parseInt(strTime % 60 + '')

   return strMinute + ":" + strSecond
  }

  //当歌曲能播放时【亦即在canplay钩子函数中】,musicAudio.value.duration才不会是NaN,才能进行歌曲长度的设置
  const changeDuration = () => {
   if (playDuration.value != musicAudio.value.duration) {

    //修改进度条的最大值
    sliderLength.value = musicAudio.value.duration

    //修改歌曲播放时间
    playDuration.value = musicAudio.value.duration
   }
  }

  //el-slider的钩子函数,拖动进度条时快进歌曲,改变当前播放进度
  const changePlayTime = (val) => {
   musicAudio.value.currentTime = val
  }

  //音量按钮点击回调
  const voiceButtonClick = () => {
   voiceMute.value = !voiceMute.value

   if (!voiceMute.value) {
    voicePower.value = 1

    musicAudio.value.volume = 1
   } else {
    voicePower.value = 0

    musicAudio.value.volume = 0
   }
  }

  //el-slider的钩子函数,用于调节音量
  const changeVoicePower = (val) => {
   musicAudio.value.volume = val

   voicePower.value = val

   if (val > 0) {
    voiceMute.value = false
   } else {
    voiceMute.value = true
   }

  }

  //播放状态下,进度条里的数值每秒递增。而Audio因为在播放状态下,currentTime会自己递增,所以不用处理
  const updatePlayTimePerSecond = () => {
   if (playState.value) {
    playTime.value += 1

    if (playTime.value >= playDuration.value) {
     //代表当前歌曲已经播放完毕,进行切歌
     musicCursor.value++

     changeMusic()
    }
   }
  }

  //切歌
  const changeMusic = () => {
   //切歌【这里的music_url是后端返回给前端的json字符串中,用于存储歌曲在线链接的属性名是:music_url,所以要实现自己的请求逻辑,将这里的music_url改为自己的即可】
   musicSource.value.src = musicState.musicArr[musicCursor.value % musicState.musicCount].music_url

   // 当刷新了url之后,需要执行load方法才能播放这个音乐
   musicAudio.value.load()

   playTime.value = musicAudio.value.currentTime

   sliderLength.value = musicAudio.value.duration

   musicAudio.value.play()

   playState.value = true
  }

  //初始化歌曲源【将这里替换成自己的请求逻辑】
  const initMusicArr = () => {
   requests.get("/Music/QueryAllMusic").then(function (res) {
    musicState.musicArr = res

    musicState.musicCount = res.length

   })
  }

  onMounted(() => {
   initMusicArr()

   //播放状态下,使播放进度自增1,以与Audio内置的currentTime相匹配
   setInterval(updatePlayTimePerSecond, 1000)

   //添加滚动事件
   window.addEventListener("scroll", operateMusicPlayer)
  })

  onUnmounted(() => {
   window.removeEventListener("scroll", operateMusicPlayer)
  })


  return {
   musicAudio,
   musicSource,
   playState,
   playTime,
   playDuration,
   sliderLength,
   musicUrl,
   voiceMute,
   voicePower,
   musicState,
   musicCursor,
   pageOffset,
   offsetThreshold,
   playButtonClick,
   lastButtonClick,
   nextButtonClick,
   voiceButtonClick,
   tooltipFormat,
   changeMusic,
   changeDuration,
   changePlayTime,
   changeVoicePower,
   updatePlayTimePerSecond,
   initMusicArr
  }
 },
}
</script>

<style scoped>

.music-container {
 position: fixed;
 justify-content: center;
 width: 280px;
 height: 110px;
 background-color: white;
 border-radius: 15px;
 bottom: 15px;
 left: 10px;
 opacity: 0;
 transition: 0.5s;
}


.music-disk {
 position: absolute;
 width: 90px;
 height: 90px;
 left: 15px;
 top: 10px;
 border-radius: 50%;
}

.music-disk-picture {
 width: 90px;
 height: 90px;
 border-radius: 50%;
 /*设置图片不可点击*/
 pointer-events: none;
}

.music-disk-playing-style {
 animation: music-disk-rotate 5s linear infinite;
}

@keyframes music-disk-rotate {
 0% {
  transform: rotate(0deg);
 }
 100% {
  transform: rotate(360deg);
 }
}

.button-group {
 position: absolute;
 width: 330px;
 height: 38px;
 left: 90px;
 bottom: 13px;
 margin-left: 10px;
}

.button-group > button {
 margin-left: 10px;
}

.play-button {
 float: left;
 width: 31px;
 height: 31px;
 padding: 4px;
 /*margin: 0px;*/
 border: 0px;
 border-radius: 50%;
 margin: 7px 0px 0px 0px;
}

.voice-button {
 float: left;
 width: 31px;
 height: 31px;
 padding: 0px;
 /*margin: 0px;*/
 border: 0px;
 border-radius: 50%;
 margin: 7px 0px 0px 0px;
 background-color: transparent;
}


.music-slider {
 position: absolute;
 top: 20px;
 left: 120px;
 width: 50%;
}

.voice-container {
 float: left;
 margin-left: 12px;
 width: 31px;
 height: 38px;
 overflow: hidden !important;
 transition: 0.5s;
}

.voice-container:hover {
 width: 160px;
}


.voice-slider {
 position: relative;
 top: 2px;
 right: -30px;
 width: 90px;
 height: 35px;
 background-color: white;
 border-radius: 10px;
 padding: 0px 15px 0px 15px;
 transition: 0.2s;
}

.audio-component {
 width: 300px;
 height: 200px;
 top: 100px;
 display: none;
}

.music-active-switch{
 opacity: 1;
}

</style>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。


以上就是关于“用Vue3怎样实现音乐播放器组件,要做什么准备”的介绍了,感谢各位的阅读,希望这篇文章能帮助大家解决问题。如果想要了解更多知识,欢迎关注恒创科技,小编每天都会为大家更新不同的知识。
上一篇: 用ElementUI中的Table怎样让内容不换行呢 下一篇: 手机怎么远程登录云服务器?