319 lines
6.9 KiB
Vue
319 lines
6.9 KiB
Vue
<template>
|
|
<div ref="playerRef"></div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
|
|
import APlayer from "APlayer";
|
|
import "aplayer/dist/APlayer.min.css";
|
|
import {
|
|
h,
|
|
ref,
|
|
reactive,
|
|
nextTick,
|
|
onMounted,
|
|
onBeforeUnmount,
|
|
watch,
|
|
} from "vue";
|
|
import { getPlayerList } from "@/api";
|
|
import { mainStore } from "@/store";
|
|
const store = mainStore();
|
|
|
|
const playerRef = ref();
|
|
const state = reactive({
|
|
instance: null,
|
|
});
|
|
const playerData = reactive({
|
|
name: null,
|
|
artist: null,
|
|
lrc: null,
|
|
});
|
|
|
|
// APlayer歌曲信息
|
|
class Audio {
|
|
// 音频艺术家
|
|
// artist: String;
|
|
// 音频名称
|
|
// name: String;
|
|
// 音频链接
|
|
// url: String;
|
|
// 音频封面
|
|
// cover: String;
|
|
// 歌词
|
|
// lrc: String;
|
|
|
|
constructor(artist, name, url, cover, lrc) {
|
|
this.artist = artist;
|
|
this.name = name;
|
|
this.url = url;
|
|
this.cover = cover;
|
|
this.lrc = lrc;
|
|
}
|
|
}
|
|
|
|
const props = defineProps({
|
|
// 开启吸底模式
|
|
fixed: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
// 开启迷你模式
|
|
mini: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
// 音频自动播放
|
|
autoplay: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
// 主题色
|
|
theme: {
|
|
type: String,
|
|
default: "#efefef",
|
|
},
|
|
// 音频循环播放
|
|
loop: {
|
|
type: String,
|
|
default: "all", //'all' | 'one' | 'none'
|
|
},
|
|
// 音频循环顺序
|
|
order: {
|
|
type: String,
|
|
default: "random", //'list' | 'random'
|
|
},
|
|
// 预加载
|
|
preload: {
|
|
type: String,
|
|
default: "auto", //'auto' | 'metadata' | 'none'
|
|
},
|
|
// 默认音量
|
|
volume: {
|
|
type: Number,
|
|
default: 0.7,
|
|
validator: (value) => {
|
|
return value >= 0 && value <= 1;
|
|
},
|
|
},
|
|
// 歌曲服务器 ( netease-网易云, tencent-qq音乐, kugou-酷狗, xiami-小米音乐, baidu-百度音乐 )
|
|
songServer: {
|
|
type: String,
|
|
default: "netease", //'netease' | 'tencent' | 'kugou' | 'xiami' | 'baidu'
|
|
},
|
|
// 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
|
songType: {
|
|
type: String,
|
|
default: "playlist",
|
|
},
|
|
// id
|
|
songId: {
|
|
type: String,
|
|
default: "7452421335",
|
|
},
|
|
// 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器
|
|
mutex: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
// 传递歌词方式
|
|
lrcType: {
|
|
type: Number,
|
|
default: 3,
|
|
},
|
|
// 列表是否默认折叠
|
|
listFolded: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
// 列表最大高度
|
|
listMaxHeight: {
|
|
type: String,
|
|
default: "420px",
|
|
},
|
|
// 存储播放器设置的 localStorage key
|
|
storageName: {
|
|
type: String,
|
|
default: "aplayer-setting",
|
|
},
|
|
});
|
|
|
|
// 初始化播放器
|
|
onMounted(() => {
|
|
nextTick(() => {
|
|
getPlayerList(props.songServer, props.songType, props.songId)
|
|
.then((res) => {
|
|
// console.log(res);
|
|
// 更改播放器加载状态
|
|
store.musicIsOk = true;
|
|
console.log("音乐加载完成");
|
|
let audioList = res.map(
|
|
(value) =>
|
|
new Audio(value.artist, value.name, value.url, value.pic, value.lrc)
|
|
);
|
|
state.instance = new APlayer({
|
|
container: playerRef.value,
|
|
fixed: props.fixed,
|
|
mini: props.mini,
|
|
autoplay: props.autoplay,
|
|
theme: props.theme,
|
|
loop: props.loop,
|
|
order: props.order,
|
|
preload: props.preload,
|
|
volume: props.volume,
|
|
mutex: props.mutex,
|
|
lrcType: props.lrcType,
|
|
listFolded: props.listFolded,
|
|
listMaxHeight: props.listMaxHeight,
|
|
storageName: props.storageName,
|
|
audio: audioList,
|
|
});
|
|
|
|
state.instance.on("play", () => {
|
|
// 播放状态
|
|
store.setPlayerState(state.instance.audio.paused);
|
|
// 储存播放器信息
|
|
store.setPlayerData(
|
|
playerRef.value.getElementsByClassName("aplayer-title")[0]
|
|
.innerHTML,
|
|
playerRef.value
|
|
.getElementsByClassName("aplayer-author")[0]
|
|
.innerHTML.split("-")[1]
|
|
.trim()
|
|
);
|
|
ElMessage({
|
|
message:
|
|
store.getPlayerData.name + " - " + store.getPlayerData.artist,
|
|
grouping: true,
|
|
icon: h(MusicOne, {
|
|
theme: "filled",
|
|
fill: "#efefef",
|
|
}),
|
|
});
|
|
});
|
|
|
|
state.instance.on("pause", () => {
|
|
// 播放状态
|
|
store.setPlayerState(state.instance.audio.paused);
|
|
});
|
|
|
|
state.instance.on("timeupdate", () => {
|
|
if (playerRef.value) {
|
|
playerData.lrc = playerRef.value.getElementsByClassName(
|
|
"aplayer-lrc-current"
|
|
)[0].innerHTML;
|
|
}
|
|
});
|
|
})
|
|
.catch(() => {
|
|
store.musicIsOk = false;
|
|
ElMessage({
|
|
message: "播放器加载失败",
|
|
grouping: true,
|
|
icon: h(PlayWrong, {
|
|
theme: "filled",
|
|
fill: "#efefef",
|
|
}),
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// 销毁播放器
|
|
onBeforeUnmount(() => {
|
|
state.instance.destroy();
|
|
});
|
|
|
|
// 切换播放暂停事件
|
|
const playToggle = () => {
|
|
state.instance.toggle();
|
|
};
|
|
|
|
// 切换音量事件
|
|
const changeVolume = (value) => {
|
|
state.instance.volume(value);
|
|
};
|
|
|
|
// 切换上下曲
|
|
const changeSongPrev = () => {
|
|
state.instance.skipBack();
|
|
};
|
|
const changeSongNext = () => {
|
|
state.instance.skipForward();
|
|
};
|
|
|
|
// 暴露子组件方法
|
|
defineExpose({ playToggle, changeVolume, changeSongPrev, changeSongNext });
|
|
|
|
// 监听歌词变化
|
|
watch(
|
|
() => playerData.lrc,
|
|
(value) => {
|
|
console.log(value);
|
|
// 储存至 pinia
|
|
store.setPlayerLrc(value);
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<style lang='scss' scoped>
|
|
.aplayer {
|
|
width: 80%;
|
|
background: transparent;
|
|
border-radius: 6px;
|
|
:deep(.aplayer-body) {
|
|
.aplayer-pic {
|
|
display: none;
|
|
}
|
|
.aplayer-info {
|
|
margin-left: 0;
|
|
background-color: #ffffff40;
|
|
border-color: transparent;
|
|
.aplayer-title {
|
|
font-size: 16px;
|
|
}
|
|
.aplayer-author {
|
|
color: #efefef;
|
|
}
|
|
.aplayer-lrc {
|
|
text-align: left;
|
|
margin: 4px 0 0 6px;
|
|
height: 38px;
|
|
&::before,
|
|
&::after {
|
|
display: none;
|
|
}
|
|
p {
|
|
color: #efefef;
|
|
}
|
|
.aplayer-lrc-current {
|
|
font-size: 0.95rem;
|
|
margin-bottom: 4px !important;
|
|
}
|
|
}
|
|
.aplayer-controller {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
:deep(.aplayer-list) {
|
|
margin-top: 6px;
|
|
ol {
|
|
li {
|
|
border-color: transparent;
|
|
&.aplayer-list-light {
|
|
background: #ffffff40;
|
|
border-radius: 6px;
|
|
}
|
|
&:hover {
|
|
background: #ffffff26 !important;
|
|
border-radius: 6px !important;
|
|
}
|
|
.aplayer-list-index,
|
|
.aplayer-list-author {
|
|
color: #efefef;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |