使用vue制作一个属于自己的音乐播放器

it2026-08-12  8

个人博客原文地址(支持代码预览) 云墨白的博客https://www.yunmobai.cn/blog/7

前言

其中在想在博客中添加音乐播放功能的时候,也考虑也其它音乐播放器插件如APlayer,页面和功能都能满足要求。而且播放页面也很好看,功能几乎都有。但是我不需要那么多功能,所以我自己尝试制作一个属于自己博客的音乐播放器。页面布局及样式参考APlayer

案例预览(点击预览云墨白-音乐播放器)

<style> .isshow { left: -66px !important; } .music-row { height: 66px; bottom: 0px; left: 0; z-index: 999; transition: all 0.5s; margin-top: 60px; } .music-row:hover { left: 0px !important; } .music-row .music { transition: all 0.3s; display: flex; justify-content: left; } .music-row .music .music-img { position: relative; height: 66px; width: 66px; cursor: pointer; } .music-row .music .music-img:hover .music-toggle { color: var(--main-5); font-size: 25px; } .music-row .music .music-img .music-toggle { width: 30px; height: 30px; font-size: 20px; color: var(--main-6); text-align: center; line-height: 30px; position: absolute; bottom: 50%; right: 50%; transform: translate(50%,50%); transition: all 0.3s; } .music-row .music .music-img .music-toggle:hover { color: var(--main-5); } .music-row .music .music-img .musicActive { bottom: 0px; right: 0px; transform: translate(0%,0%); } .music-row .music .music-content { width: 334px; height: 66px; border-top: 1px solid #e9e9e9; padding: 3px 5px; background-color: #fff; box-sizing: border-box; position: relative; display: flex; flex-wrap: wrap; } .music-row .music .music-content .music-list { width: 100%; height: 100px; background-color: #fff; position: absolute; top: -100px; left: 0; margin: 0; padding: 5px; overflow: auto; box-sizing: border-box; border-bottom: 1px solid #ccc; border-top-left-radius: 4px; border-top-right-radius: 4px; } .music-row .music .music-content .music-list li { height: 30px; line-height: 30px; font-size: 14px; padding: 0 4px; margin: 2px 0; color: var(--main-6); background-color: #f8f9f9; transition: all 0.3s; cursor: pointer; display: flex; justify-content: space-between; } .music-row .music .music-content .music-list li span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .music-row .music .music-content .active { color: #f56c6c !important; border-left: 3px solid #f56c6c; } .music-row .music .music-content .cont-top { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 15px; width: 65%; height: 40px; line-height: 40px; } .music-row .music .music-content .cont-cont { position: absolute; top: 3px; right: 0; } .music-row .music .music-content .cont-cont .cont-itme { display: inline-block; width: 30px; height: 40px; text-align: center; line-height: 40px; font-size: 18px; transition: all 0.2s; } .music-row .music .music-content .cont-cont .cont-itme:hover { cursor: pointer; color: #ccc; } .music-row .music .music-content .cont-bottom { position: absolute; bottom: 0; left: 0; width: 100%; height: 28px; display: flex; justify-content: left; padding: 0 5px; box-sizing: border-box; } .music-row .music .music-content .cont-bottom .bottom-progress { width: 80%; display: flex; align-items: center; } .music-row .music .music-content .cont-bottom .time { font-size: 12px; } .music-row .music .music-content .cont-bottom .music-func { line-height: 28px; } .music-row .music .music-content .cont-bottom .music-func span { margin: 0 3px; cursor: pointer; } .music-row .music .music-btn { height: 66px; width: 18px; background-color: #ccc; cursor: pointer; line-height: 66px; border-bottom-right-radius: 4px; border-top-right-radius: 4px; } </style> <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/theme-chalk/index.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/index.js"></script> <div id="app"> <el-row class="music-row" :class="{isshow:isShow}"> <el-col :md="24" class="music"> <!-- <audio id="music" :src="musicInfo.url"></audio> --> <!-- 音乐图片 --> <div class="music-img"> <el-avatar class="music-img" :size="66" shape="square" :src="musicInfo.pic"> <i class="el-icon-loading"></i> <!-- <img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/> --> </el-avatar> <span :class="{musicActive:isPlay}" @click="pause" class="iconfont music-toggle"><span :class="isPlay?'el-icon-video-pause':'el-icon-video-play'"></span> </span></div> <!-- 展开模块 --> <transition name="el-zoom-in-center"> <div v-show="muIsShow" class="music-content"> <transition name="el-zoom-in-bottom"> <!-- 音乐列表模块 --> <div v-show="isList" class="music-list scrollbar"> <el-scrollbar style="width: 100%; height: 100%;"> <ul style="padding:0"> <li :class="{active:index==ind}" @click="index=ind" v-for="(item,ind) of musics" :key="item.musicId"> <span> {{ind+1}} <span>{{item.title}}</span> </span> <span>{{item.name}}</span> </li> </ul> </el-scrollbar> </div> </transition> <!-- 标题 作者 --> <div class="cont-top"> <span>{{musics[index].title}}</span> <span>---</span> <span>{{musics[index].name}}</span> </div> <!--暂停 快进 --> <div class="cont-cont"> <span class="cont-itme el-icon-d-arrow-left" @click="index=index==0?musics.length-1:index-1"></span> <span @click="pause" class="cont-itme iconfont" :class="isPlay?'el-icon-video-pause':'el-icon-video-play'"></span> <span class="cont-itme el-icon-d-arrow-right" @click="index=index==musics.length-1?0:index+1"></span> <span class="cont-itme el-icon-menu" @click="isList=!isList"></span> </div> <!-- 音乐拖动条 时间 --> <div class="cont-bottom"> <div class="bottom-progress"> <el-slider style="width:80%" tooltip-class="content-bg8" :format-tooltip="transTime" @change="getVal()" input-size="mini" :min="0" :max="max" v-model="numb"></el-slider> <!-- <input class="bottom-range" v-model="numb" type="range" min="0" :max="max" @input="getVal()" :style="{background: '-webkit-linear-gradient(top, var(--main-5), var(--main-5)) 0% 0% / '+ numb*100/max +'% 100% no-repeat'}"/> --> <span class="time" style="padding-left:10px">{{newTime}}</span> <span class="time">/</span> <span class="time">{{time}}</span> </div> <!-- 循环播放 --> <div class="music-func"> <span @click="cycle=cycle==2?0:cycle+1" class="cont-itme iconfont" :class="cycle==0?'el-icon-finished':cycle==1?'el-icon-refresh':'el-icon-sort'"></span> </div> </div> </div> </transition> <!-- 扩展栏 --> <div class="music-btn" @click="MuBtnClick"> <i :class="muIsShow?'el-icon-arrow-left':'el-icon-arrow-right'"></i> </div> </el-col> </el-row> </div> <script> var Main = { data() { return { index: 0, //播放列表 muIsShow: false, //是否显示 isPlay: false, //是否播放 canplay: false, //是否能播放 loading: false, //是否自动播放 cycle: 0, numb: 0, time: "00:00", newTime: "00:00", max: 0, audio: "", musicInfo: {}, isList: false, isShow: false, setTimeout: null, musics: [ { "music_id": "1463165983", "title": "最美的期待", "name": "周笔畅", "type": "netease", "url":'https://www.0dutv.com/plug/down/up2.php/212877015.mp3', "pic":'https://p.pstatp.com/origin/1372100011fb653db9634' }, { "music_id": "515453363", "title": "过客", "name": "阿涵", "type": "netease", "url":'https://www.0dutv.com/plug/down/up2.php/109717925.mp3', "pic":'https://p.pstatp.com/origin/1372100011fb653db9634' }, ] } }, methods: { // 打开和关闭音乐收缩栏 MuBtnClick() { this.muIsShow = !this.muIsShow; this.hidden(1500); }, hidden(time) { if (this.muIsShow == false) { this.setTimeout = setTimeout(() => { this.isShow = true; }, time); } else { clearTimeout(this.setTimeout); this.isShow = false; } }, // 播放暂停 pause() { if (this.audio !== null && this.canplay) { this.loading = true; if (this.audio.paused) { this.audio.play(); // 播放 this.isPlay = true; } else { this.audio.pause(); // 暂停 this.isPlay = false; console.log("暂停被调用了"); } } else { this.$message({ showClose: true, message: "音乐还没有加载成功呢!", type: "warning", }); } }, // 快进音乐 getVal() { if (!this.audio.paused || this.audio.currentTime != 0) { this.audio.currentTime = this.numb; if (this.numb == Math.floor(this.max)) { this.audio.pause(); this.isPlay = false; } } }, // 获取音乐总时长 getTime() { let time = this.audio.duration; this.max = time; //总共时长的秒数 this.time = this.transTime(time); }, // 时间格式化位00:00 formatTime(value) { 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; }, // 把毫秒变成时分秒 transTime(value) { let time = ""; let h = parseInt(value / 3600); value %= 3600; let m = parseInt(value / 60); let s = parseInt(value % 60); if (h > 0) { time = this.formatTime(h + ":" + m + ":" + s); } else { time = this.formatTime(m + ":" + s); } return time; }, getMusic() { if (!this.musics[this.index].pause) { this.musicInfo = this.musics[this.index] this.audio.src = this.musics[this.index].url; // console.log("获取音乐"); // const qs = require("qs"); // let that = this; // console.log(that.musics[that.index].type); // this.$post( // "/music", // qs.stringify({ // input: that.musics[that.index].music_id, // filter: "id", // type: that.musics[that.index].type, // page: 1, // }) // ) // .then(function(res) { // that.musicInfo = res.data[0]; // that.audio.src = that.musicInfo.url; // }) // .catch(function(error) { // that.audio.pause(); // 暂停 // that.isPlay = false; // }); } else { console.log(this.index); this.musicInfo = { title: this.musics[this.index].title, author: this.musics[this.index].name, pic: this.musics[this.index].img, url: this.musics[this.index].url, }; this.audio.src = this.musics[this.index].url; } }, // 获取我的音乐列表 getList() { this.index = Math.floor(Math.random() * this.musics.length); this.length = this.musics.length; this.getMusic(); // let that = this; // this.$get("url") // .then(function (res) { // that.musics = res.data; // that.index = Math.floor(Math.random() * that.musics.length); // that.length = that.musics.length; // that.getMusic(); // }) // .catch(function (error) {}); }, mError() { if (this.loading) { console.log("出错"); this.$message({ showClose: true, message: "播放错误,自动播放下一首", type: "error", }); if (this.musics[this.index].musicInfo) { delete this.musics[this.index].musicInfo; } this.index = this.index == this.musics.length - 1 ? 0 : this.index + 1; } }, mCanplay() { this.canplay = true; if (this.loading) { this.audio.play(); // 播放 this.isPlay = true; } this.getTime(); }, mTimeUpdate() { this.numb = this.audio.currentTime; this.newTime = this.transTime(this.audio.currentTime); }, mEnded() { if (this.cycle == 0) { this.audio.pause(); // 暂停 this.isPlay = false; } else if (this.cycle == 1) { this.audio.play(); // 播放 this.isPlay = true; } else { this.index = this.index == this.musics.length - 1 ? 0 : this.index + 1; } }, }, mounted() { this.hidden(5000); let that = this; }, created() { // this.audio=document.getElementById('music') this.audio = document.createElement("audio"); this.getList(); let that = this; this.audio.addEventListener("canplay", that.mCanplay, false), this.audio.addEventListener("timeupdate", that.mTimeUpdate, false); this.audio.addEventListener("ended", that.mEnded, false); this.audio.addEventListener("error", that.mError, false); }, beforeDestroy() { let that=this this.audio.removeEventListener("canplay", that.mCanplay); this.audio.removeEventListener("ended", that.mEnded); this.audio.removeEventListener("error", that.mError); this.audio.removeEventListener("timeupdate", that.mTimeUpdate); }, watch: { index(val) { if (this.loading) { this.audio.play(); // 播放 this.isPlay = true; } this.canplay = false; this.audio.currentTime = 0; // this.audio.pause(); this.audio.src = ""; this.getMusic(); }, }, } var Ctor = Vue.extend(Main) new Ctor().$mount(document.getElementById('app')) </script>

了解audio

html标签

<audio src="http://www.0dutv.com/plug/down/up2.php/109717925.mp3" controls="controls"> Your browser does not support the audio element. </audio>

属性

属性值描述autoplayautoplay如果出现该属性,则音频在就绪后马上播放。controlscontrols如果出现该属性,则向用户显示控件,比如播放按钮。looploop如果出现该属性,则每当音频结束时重新开始播放。mutedmuted规定视频输出应该被静音。preloadpreload如果出现该属性,则音频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。srcurl要播放的音频的 URL。

内容来源—W3School

js创建(本案例使用)

//创建audio,不会在页面中显示。 var audio=document.createElement("audio"); //设置src,播放地址。 audio.src ='http://url'

事件

属性值描述oncanplayscript当文件就绪可以开始播放时运行的脚本(缓冲已足够开始时)。oncanplaythroughscript当媒介能够无需因缓冲而停止即可播放至结尾时运行的脚本。onendedscript当媒介已到达结尾时运行的脚本(可发送类似“感谢观看”之类的消息onpausescript当媒介被用户或程序暂停时运行的脚本。onplayscript当媒介已就绪可以开始播放时运行的脚本。onplayingscript当媒介已开始播放时运行的脚本。onprogressscript当浏览器正在获取媒介数据时运行的脚本。ontimeupdatescript当播放位置改变时(比如当用户快进到媒介中一个不同的位置时)运行的脚本。

内容来源—W3School

案例准备

格式化时间

// 获取音乐总时长 getTime() { let time = this.audio.duration; this.max = time; //总共时长的秒数 this.time = this.transTime(time); }, // 时间格式化位00:00 formatTime(value) { 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; }, // 把毫秒变成时分秒 transTime(value) { let time = ""; let h = parseInt(value / 3600); value %= 3600; let m = parseInt(value / 60); let s = parseInt(value % 60); if (h > 0) { time = this.formatTime(h + ":" + m + ":" + s); } else { time = this.formatTime(m + ":" + s); } return time; },

创建及绑定事件

created() { // 创建Audio this.audio = document.createElement("audio"); this.getList(); let that = this; // 当音乐准备就绪时的操作 this.audio.addEventListener( "canplay", function () { console.log("加载成功"); console.log(that.musicInfo.url); that.canplay = true; //防止自动播放 if (that.loading) { that.audio.play(); // 播放 that.isPlay = true; } that.getTime(); // that.pause() }, false ), //快进时的操作,同步时间 this.audio.addEventListener( "timeupdate", function () { that.numb = that.audio.currentTime; that.newTime = that.transTime(that.audio.currentTime); }, false ); //当音乐播放到结束后的操作, this.audio.addEventListener( "ended", function () { if (that.cycle == 0) { that.audio.pause(); // 暂停 that.isPlay = false; } else if (that.cycle == 1) { that.audio.play(); // 播放 that.isPlay = true; } else { that.index == that.musics.length - 1 ? 0 : that.index + 1; } }, false ); },

播放暂停、快进

// 播放暂停 pause() { if (this.audio !== null && this.canplay) { this.loading = true; if (this.audio.paused) { this.audio.play(); // 播放 this.isPlay = true; } else { this.audio.pause(); // 暂停 this.isPlay = false; console.log("暂停被调用了"); } } else { this.$message({ showClose: true, message: "音乐还没有加载成功呢!", type: "warning", }); } }, // 快进音乐 getVal() { if (!this.audio.paused || this.audio.currentTime != 0) { this.audio.currentTime = this.numb; if (this.numb == Math.floor(this.max)) { this.audio.pause(); this.isPlay = false; } } },

切换

主要时通过监听器,监听音乐id的变化来切换歌曲

watch: { index(val) { if (this.loading) { this.audio.play(); // 播放 this.isPlay = true; } this.canplay = false; this.audio.currentTime = 0; // this.audio.pause(); this.audio.src = ""; this.getMusic(); }, },
最新回复(0)