个人博客原文地址(支持代码预览) https://gitee.com/baymaxsjj
前言
其中在想在博客中添加音乐播放功能的时候,也考虑也其它音乐播放器插件如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:00formatTime(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=thisthis.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>
属性
属性 | 值 | 描述 |
---|---|---|
autoplay | autoplay | 如果出现该属性,则音频在就绪后马上播放。 |
controls | controls | 如果出现该属性,则向用户显示控件,比如播放按钮。 |
loop | loop | 如果出现该属性,则每当音频结束时重新开始播放。 |
muted | muted | 规定视频输出应该被静音。 |
preload | preload | 如果出现该属性,则音频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。 |
src | url | 要播放的音频的 URL。 |
内容来源—W3School
js创建(本案例使用)
//创建audio,不会在页面中显示。var audio=document.createElement("audio");
//设置src,播放地址。
audio.src ='http://url'
事件
属性 | 值 | 描述 |
---|---|---|
oncanplay | script | 当文件就绪可以开始播放时运行的脚本(缓冲已足够开始时)。 |
oncanplaythrough | script | 当媒介能够无需因缓冲而停止即可播放至结尾时运行的脚本。 |
onended | script | 当媒介已到达结尾时运行的脚本(可发送类似“感谢观看”之类的消息 |
onpause | script | 当媒介被用户或程序暂停时运行的脚本。 |
onplay | script | 当媒介已就绪可以开始播放时运行的脚本。 |
onplaying | script | 当媒介已开始播放时运行的脚本。 |
onprogress | script | 当浏览器正在获取媒介数据时运行的脚本。 |
ontimeupdate | script | 当播放位置改变时(比如当用户快进到媒介中一个不同的位置时)运行的脚本。 |
内容来源—W3School
案例准备
格式化时间
// 获取音乐总时长getTime() {let time = this.audio.duration;this.max = time;//总共时长的秒数this.time = this.transTime(time);},// 时间格式化位00:00formatTime(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();},},