Homepage-imsyy/src/components/Player.vue

289 lines
6.4 KiB
Vue

<template>
<APlayer
v-if="playList[0]"
ref="player"
:audio="playList"
:autoplay="store.playerAutoplay"
:theme="theme"
:autoSwitch="false"
:loop="store.playerLoop"
:order="store.playerOrder"
:volume="volume"
:showLrc="true"
:listFolded="listFolded"
:listMaxHeight="listMaxHeight"
:noticeSwitch="false"
@play="onPlay"
@pause="onPause"
@timeupdate="onTimeUp"
@error="loadMusicError"
/>
</template>
<script setup>
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
import { getPlayerList } from "@/api";
import { mainStore } from "@/store";
import APlayer from "@worstone/vue-aplayer";
const store = mainStore();
// 获取播放器 DOM
const player = ref(null);
// 歌曲播放列表
const playList = ref([]);
// 歌曲播放项
const playIndex = ref(0);
// 配置项
const props = defineProps({
// 主题色
theme: {
type: String,
default: "#efefef",
},
// 默认音量
volume: {
type: Number,
default: 0.7,
validator: (value) => {
return value >= 0 && value <= 1;
},
},
// 歌曲服务器 ( netease-网易云, tencent-qq音乐 )
songServer: {
type: String,
default: "netease", //'netease' | 'tencent'
},
// 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
songType: {
type: String,
default: "playlist",
},
// id
songId: {
type: String,
default: "7452421335",
},
// 列表是否默认折叠
listFolded: {
type: Boolean,
default: false,
},
// 列表最大高度
listMaxHeight: {
type: Number,
default: 420,
},
});
const listHeight = computed(() => {
return props.listMaxHeight + "px";
});
// 初始化播放器
onMounted(() => {
nextTick(() => {
try {
getPlayerList(props.songServer, props.songType, props.songId).then((res) => {
console.log(res);
// 更改播放器加载状态
store.musicIsOk = true;
// 生成歌单
playList.value = res;
console.log("音乐加载完成");
console.log(playList.value);
console.log(playIndex.value, playList.value.length, props.volume);
});
} catch (err) {
console.error(err);
store.musicIsOk = false;
ElMessage({
message: "播放器加载失败",
grouping: true,
icon: h(PlayWrong, {
theme: "filled",
fill: "#efefef",
}),
});
}
});
});
// 播放
const onPlay = () => {
console.log("播放");
playIndex.value = player.value.aplayer.index;
// 播放状态
store.setPlayerState(player.value.audioRef.paused);
// 储存播放器信息
store.setPlayerData(playList.value[playIndex.value].name, playList.value[playIndex.value].artist);
ElMessage({
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
grouping: true,
icon: h(MusicOne, {
theme: "filled",
fill: "#efefef",
}),
});
};
// 暂停
const onPause = () => {
store.setPlayerState(player.value.audioRef.paused);
};
// 音频时间更新事件
const onTimeUp = () => {
let lyrics = player.value.aplayer.lyrics[playIndex.value];
let lyricIndex = player.value.aplayer.lyricIndex;
if (!lyrics || !lyrics[lyricIndex]) {
return;
}
let lrc = lyrics[lyricIndex][1];
if (lrc === "Loading") {
lrc = "歌词加载中";
} else if (lrc === "Not available") {
lrc = "歌词加载失败";
}
store.setPlayerLrc(lrc);
};
// 切换播放暂停事件
const playToggle = () => {
player.value.toggle();
};
// 切换音量事件
const changeVolume = (value) => {
player.value.setVolume(value, false);
};
// 切换上下曲
const changeSong = (type) => {
type === 0 ? player.value.skipBack() : player.value.skipForward();
nextTick(() => {
player.value.play();
});
};
// 切换歌曲列表状态
const toggleList = () => {
player.value.toggleList();
};
// 加载音频错误
const loadMusicError = () => {
let notice = "";
if (playList.value.length > 1) {
notice = "播放歌曲出现错误,播放器将在 2s 后进行下一首";
} else {
notice = "播放歌曲出现错误";
}
ElMessage({
message: notice,
grouping: true,
icon: h(PlayWrong, {
theme: "filled",
fill: "#EFEFEF",
duration: 2000,
}),
});
console.error(
"播放歌曲: " + player.value.aplayer.audio[player.value.aplayer.index].name + " 出现错误",
);
};
// 暴露子组件方法
defineExpose({ playToggle, changeVolume, changeSong, toggleList });
</script>
<style lang="scss" scoped>
.aplayer {
width: 80%;
border-radius: 6px;
font-family: "HarmonyOS_Regular", sans-serif !important;
:deep(.aplayer-body) {
background-color: transparent;
.aplayer-pic {
display: none;
}
.aplayer-info {
margin-left: 0;
background-color: #ffffff40;
border-color: transparent !important;
.aplayer-music {
flex-grow: initial;
margin-bottom: 2px;
overflow: initial;
.aplayer-title {
font-size: 16px;
margin-right: 6px;
}
.aplayer-author {
color: #efefef;
}
}
.aplayer-lrc {
text-align: left;
margin: 7px 0 6px 6px;
height: 44px;
mask: linear-gradient(
#fff 15%,
#fff 85%,
hsla(0deg, 0%, 100%, 0.6) 90%,
hsla(0deg, 0%, 100%, 0)
);
-webkit-mask: linear-gradient(
#fff 15%,
#fff 85%,
hsla(0deg, 0%, 100%, 0.6) 90%,
hsla(0deg, 0%, 100%, 0)
);
&::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;
height: v-bind(listHeight);
background-color: transparent;
ol {
&::-webkit-scrollbar-track {
background-color: transparent;
}
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>