兴趣乃学习的动力,想自己动手写个音乐播放器,查了网上一些博客,最终东拼西凑写了一个。网上有网易云的接口,这里不多赘述了。
整体项目代码挺多的,在这里就只挑选音乐播放和切换音乐来记录了。
https://github.com/gloryin2016/manageplatform
把搜索后获取的音乐列表,将其存入store;通过index来切换不同的歌曲。
HTML的audio属性参考 https://www.jianshu.com/p/1fe701c9179f
//进度条直接用的element的slider,修改样式颜色即可
data
data() {
return {
playing: false,
index: 0, // 当前播放歌曲在列表中的下标
currentTime: "00:00", // 当前播放时间
totalTime: "00:00", // 总播放时间
bufferedScaleX: 0, // 缓存进度
processWidth: 0, //播放百分比
progressScaleX: 0, // 播放进度
thumbTranslateX: 0, // 进度条滑块位置
silderBoxX: 0, //进度条滑块位置-->采用element后的
volume: 50, // 音量
error: "", // 报错内容
playType: '1', // 播放类型:1-列表循环,2-随机播放,3-单曲循环
//播放列表
songList: [
{
albumId: 75612550,
albumTitle: "辞.九门回忆",
artistsName: "解忧草",
cover: "",
finalTime: "04:00",
id: 1347524822,
index: 6,
mvId: 0,
name: "辞.九门回忆",
sort: "07",
url: "https://music.163.com/song/media/outer/url?id=1347524822.mp3",
},
{
albumId: 85511857,
albumTitle: "谪仙",
artistsName: "伊格赛听",
cover: "",
finalTime: "02:0",
id: 1421256202,
index: 0,
mvId: 0,
name: "谪仙",
sort: "01",
url: "https://music.163.com/song/media/outer/url?id=1421256202.mp3",
},
{
albumId: 35172219,
albumTitle: "君の名は - 黄昏之时",
artistsName: "Frank_Jiang",
cover:
"https://p1.music.126.net/YppJiMHyrLc7tDkj6jUttg==/109951162858188597.jpg",
finalTime: "03:00",
id: 459116892,
index: 5,
mvId: 0,
name: "黄昏之时(FRANKOWO Bootleg)",
sort: "06",
url: "https://music.163.com/song/media/outer/url?id=459116892.mp3",
},
],
//当前播放歌曲
songInfo: {
albumId: 75612550,
albumTitle: "辞.九门回忆",
artistsName: "解忧草/冰幽",
cover: "",
finalTime: "04:00",
id: 1347524822,
index: 6,
mvId: 0,
name: "辞.九门回忆",
sort: "07",
url: "https://music.163.com/song/media/outer/url?id=1347524822.mp3",
},
lyricsObjArr: [],//歌词
lyricIndex: 0,歌词索引
};
},
JS
mounted() {
audio = document.getElementById("audio");
this.Init();
},
method: {
Init(){
this.songInfo = this.songList[0];
this.audioInit();
}
//播放与暂停
play() {
if (this.playing) {
// 播放中,点击则为暂停
this.playing = false;
audio.pause();
} else {
// 暂停中,点击则为播放
this.playing = true;
audio.play();
}
},
audioInit() {
let _this = this;
let progressL = this.$refs.track.offsetWidth; // 进度条总长
// 播放位置改变时触发[注意:播放和调整指示定位时都会触发](主要事件)
audio.addEventListener("timeupdate", () => {
// 当前播放时间
_this.currentTime = _this.timeToString(audio.currentTime);
let compareTime = audio.currentTime;
for (let i = 0; i < _this.lyricsObjArr.length; i++) {
if (compareTime > parseInt(_this.lyricsObjArr[i].time)) {
const index = _this.$refs.lyric[i].dataset.index;
if (i === parseInt(index)) {
_this.lyricIndex = i;
}
}
}
// 总播放时间
_this.totalTime = _this.timeToString(audio.duration);
// 当前播放进度百分比
let precent = audio.currentTime / audio.duration || 0;
// 当前播放进度
_this.progressScaleX = precent.toFixed(3);
_this.processWidth = precent.toFixed(2) * 100;
// 当前缓存进度
// 已缓存时间
let buffered = audio.buffered.length
? audio.buffered.end(audio.buffered.length - 1)
: 0;
_this.bufferedScaleX = (buffered / audio.duration).toFixed(3);
// 当前进度按钮位置
_this.thumbTranslateX = (precent * progressL).toFixed(3);
});
// 音频或视频能够不停顿地一直播放
audio.addEventListener("canplaythrough", () => {
console.log("canplaythrough");
});
// 音频或视频的时长已改变
audio.addEventListener("durationchange", () => {
console.log("durationchange");
_this.totalTime = _this.timeToString(audio.duration);
});
// 在音频或视频终止加载时触发,包括终止当前播放(未加载完)进行下一首播放时也会触发
audio.addEventListener("abort", () => {
console.log("abort");
});
// 在音频或视频加载发生错误时触发
audio.addEventListener("error", () => {
console.log("error");
console.log("-----networkState---------", audio.networkState);
console.log("-----readyState---------", audio.readyState);
switch (audio.networkState) {
case "0":
_this.error = "尚未初始化";
break;
case "1":
_this.error = "正在下载数据";
break;
case "3":
_this.error = "未找到资源";
break;
}
audio.readyState == "0" && (_this.error = "音频地址错误");
setTimeout(() => {
_this.error = "";
}, 3000);
});
// 播放结束
audio.addEventListener(
"ended",
() => {
console.log("ended");
switch (parseInt(_this.playType)) {
case 1: // 列表循环
_this.index =
_this.index + 1 >= _this.songList.length ? 0 : _this.index + 1;
break;
case 2: // 随机播放
_this.index = Math.floor(Math.random() * _this.songList.length);
break;
case 3: // 单曲循环
break;
}
_this.songInfo = _this.songList[_this.index];
this.$store.dispatch("setSongIndex", _this.index); //在vuex存入当前播放歌曲的index
this.GetLyric(_this.songInfo.id);//获取歌词的接口
_this.thumbSlide = true;
setTimeout(() => {
audio.play();
}, 100);
// 解决因为transition的回弹bug
setTimeout(() => {
_this.thumbSlide = false;
}, 1000);
},
true
);
},
},
// 秒值转字符串
timeToString(param) {
param = parseInt(param);
let hh = "",
mm = "",
ss = "";
if (param >= 0 && param < 60) {
param < 10 ? (ss = "0" + param) : (ss = param);
return "00:" + ss;
} else if (param >= 60 && param < 3600) {
mm = parseInt(param / 60);
mm < 10 ? (mm = "0" + mm) : mm;
param - parseInt(mm * 60) < 10
? (ss = "0" + String(param - parseInt(mm * 60)))
: (ss = param - parseInt(mm * 60));
return mm + ":" + ss;
}
},
//上下首封装
skipFn(type) {
switch (parseInt(this.playType)) {
case 2: // 随机播放
this.index = Math.floor(Math.random() * this.songList.length);
break;
default:
if (type == "skipBack") {
this.index - 1 >= 0 ? this.index-- : 0;
} else {
this.index =
this.index + 1 >= this.songList.length
? this.songList.length - 1
: this.index + 1;
}
break;
}
this.songInfo = this.songList[this.index];
this.$store.dispatch("setSongIndex", this.index);
this.playing = true;
setTimeout(() => {
this.totalTime = "00:00";
audio.play();
}, 100);
},