Vue3实现简易音乐播放器组件
更新时间:2022年8月14日 15:54 点击:649 作者:cb414
前言
用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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
原文出处:https://blog.csdn.net/weixin_41043607/article/details/124604
相关文章
- 这篇文章主要介绍了浅谈vue2的$refs在vue3组合式API中的替代方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-18
- 今天将从 Vue 的入口文件开始,看看声明了一个 Vue 的单文件之后是如何被 compile-core 编译核心模块编译成渲染函数的。下面小编讲解并附上代码分析展现在文章里,感兴趣的小伙伴不要错过奥...2021-09-25
- 这篇文章主要介绍了vue3弹出层V3Popup实例详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-04
- 源码的重要性相信不用再多说什么了吧,特别是用Vue 框架的,一般在面试的时候面试官多多少少都会考察源码层面的内容,下面这篇文章主要给大家介绍了关于vue3源码剖析之简单实现的相关资料,需要的朋友可以参考下...2021-09-07
- 这篇文章主要介绍了Vue3中的三种函数,分别对reactive函数toRef函数以及ref函数原理及使用作了简单介绍,有需要的朋友可以借鉴参考下...2021-09-24
- 这篇文章主要为大家详细介绍了原生JS音乐播放器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-01-26
- 这篇文章主要介绍了jQuery开发仿QQ版的音乐播放器,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-10
- 这篇文章主要介绍利用Vue3 创建Vue CLI 项目,下面文章内容附有官方文档链接,安装过程,需要的可以参考一下...2021-10-18
- 这篇文章主要给大家分享的是Vue3的几个优势,Vue3仍然在源码、性能和语法 API 三个大的方面进行了优化,下面我们一起进入文章看看具体详情吧...2021-10-26
- 这篇文章主要给大家介绍了关于vue3封装放大镜组件的相关资料,封装之后,使用起来就更简单了,一个组件一行就可以,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2021-09-20
Android GSYVideoPlayer视频播放器功能的实现
这篇文章主要介绍了Android GSYVideoPlayer视频播放器功能的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-31- 这篇文章主要介绍了使用Vue3进行数据绑定及显示列表数据,整篇文章围绕Vue3进行数据绑定及显示列表数据的想换自来哦展开内容,需要的小伙伴可以参考一下...2021-10-23
- 这篇文章主要介绍了利用vue3+ts实现管理后台(增删改查),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-30
- 这篇文章主要介绍了40行代码把Vue3的响应式集成进React做状态管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-05-20
- 这篇文章主要介绍了详解vue3 沙箱机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-15
- 下面我来给各位同学介绍一个php获取优酷土豆页面中视频swf播放器地址,临时写的不够完善各位朋友可完善与我分享哦。 代码如下 复制代码 项...2016-11-25
- 这篇文章主要介绍了WinForm实现仿视频播放器左下角滚动新闻效果的方法,涉及WinForm窗口滚动字幕设置的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 这篇文章我们从 ast 生成时调用的 baseParse 函数分析,再到 baseParse 返回 createRoot 的调用结果,一直到细化的讲解了 parseChildren 解析子节点函数中的其中某一个具体解析器的执行过程。最后通过一个简单模板举例,需要的朋友可以参考下...2021-09-25
- 这篇文章主要为大家详细介绍了iOS实现音乐播放器图片旋转,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-12-08
- 这篇文章主要介绍了Vue3 响应式侦听与计算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-11