feat: 替换 vue3-aplayer 插件,并添加播放器设置选项

This commit is contained in:
first19326 2024-01-02 02:58:01 +08:00
parent 78e0d0505a
commit d085ccc832
7 changed files with 324 additions and 499 deletions

View File

@ -14,6 +14,7 @@
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix" "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix"
}, },
"dependencies": { "dependencies": {
"@worstone/vue-aplayer": "^1.0.4",
"aplayer": "^1.10.1", "aplayer": "^1.10.1",
"axios": "^1.1.3", "axios": "^1.1.3",
"element-plus": "^2.2.18", "element-plus": "^2.2.18",
@ -21,8 +22,7 @@
"pinia": "^2.0.23", "pinia": "^2.0.23",
"pinia-plugin-persistedstate": "^3.0.0", "pinia-plugin-persistedstate": "^3.0.0",
"swiper": "^9.3.2", "swiper": "^9.3.2",
"vue": "^3.3.4", "vue": "^3.3.4"
"vue3-aplayer": "^1.7.3"
}, },
"devDependencies": { "devDependencies": {
"@icon-park/vue-next": "^1.4.2", "@icon-park/vue-next": "^1.4.2",

File diff suppressed because it is too large Load Diff

View File

@ -22,18 +22,18 @@ export const getPlayerList = async (server, type, id) => {
).replace("http://", "https://"); ).replace("http://", "https://");
return data.map((v, i) => ({ return data.map((v, i) => ({
title: v.name || v.title, name: v.name || v.title,
artist: v.artist || v.author, artist: v.artist || v.author,
src: domain + jsonpData.req_0.data.midurlinfo[i].purl, url: domain + jsonpData.req_0.data.midurlinfo[i].purl,
pic: v.pic, cover: v.cover || v.pic,
lrc: v.lrc, lrc: v.lrc,
})); }));
} else { } else {
return data.map((v) => ({ return data.map((v) => ({
title: v.name || v.title, name: v.name || v.title,
artist: v.artist || v.author, artist: v.artist || v.author,
src: v.url, url: v.url,
pic: v.pic, cover: v.cover || v.pic,
lrc: v.lrc, lrc: v.lrc,
})); }));
} }

View File

@ -43,7 +43,7 @@
</div> </div>
<!-- 音乐列表弹窗 --> <!-- 音乐列表弹窗 -->
<Transition name="fade" mode="out-in"> <Transition name="fade" mode="out-in">
<div class="music-list" v-show="musicListShow" @click="musicListShow = false"> <div class="music-list" v-show="musicListShow" @click="closeMusicList()">
<Transition name="zoom"> <Transition name="zoom">
<div class="list" v-show="musicListShow" @click.stop> <div class="list" v-show="musicListShow" @click.stop>
<close-one <close-one
@ -51,7 +51,7 @@
theme="filled" theme="filled"
size="28" size="28"
fill="#ffffff60" fill="#ffffff60"
@click="musicListShow = false" @click="closeMusicList()"
/> />
<Player <Player
ref="playerRef" ref="playerRef"
@ -59,7 +59,6 @@
:songType="playerData.type" :songType="playerData.type"
:songId="playerData.id" :songId="playerData.id"
:volume="volumeNum" :volume="volumeNum"
:shuffle="false"
/> />
</div> </div>
</Transition> </Transition>
@ -98,6 +97,13 @@ const playerData = reactive({
// //
const openMusicList = () => { const openMusicList = () => {
musicListShow.value = true; musicListShow.value = true;
playerRef.value.toggleList();
};
//
const closeMusicList = () => {
musicListShow.value = false;
playerRef.value.toggleList();
}; };
// //

View File

@ -1,21 +1,21 @@
<template> <template>
<aplayer <APlayer
showLrc
ref="player"
v-if="playList[0]" v-if="playList[0]"
:music="playList[playIndex]" ref="player"
:list="playList" :audio="playList"
:autoplay="autoplay" :autoplay="store.playerAutoplay"
:theme="theme" :theme="theme"
:repeat="repeat" :autoSwitch="false"
:shuffle="shuffle" :loop="store.playerLoop"
:listMaxHeight="listMaxHeight" :order="store.playerOrder"
:listFolded="listFolded"
:volume="volume" :volume="volume"
:showLrc="true"
:listFolded="listFolded"
:listMaxHeight="listMaxHeight"
:noticeSwitch="false"
@play="onPlay" @play="onPlay"
@pause="onPause" @pause="onPause"
@timeupdate="onTimeUp" @timeupdate="onTimeUp"
@onSelectSong="onSelectSong"
@error="loadMusicError" @error="loadMusicError"
/> />
</template> </template>
@ -24,7 +24,7 @@
import { MusicOne, PlayWrong } from "@icon-park/vue-next"; import { MusicOne, PlayWrong } from "@icon-park/vue-next";
import { getPlayerList } from "@/api"; import { getPlayerList } from "@/api";
import { mainStore } from "@/store"; import { mainStore } from "@/store";
import aplayer from "vue3-aplayer"; import APlayer from "@worstone/vue-aplayer";
const store = mainStore(); const store = mainStore();
@ -36,32 +36,14 @@ const playList = ref([]);
// //
const playIndex = ref(0); const playIndex = ref(0);
const playListCount = ref(0);
const skipTimeout = ref(null);
// //
const props = defineProps({ const props = defineProps({
//
autoplay: {
type: Boolean,
default: false,
},
// //
theme: { theme: {
type: String, type: String,
default: "#efefef", default: "#efefef",
}, },
//
repeat: {
type: String,
default: "list", //'list' | 'music' | 'none'
},
//
shuffle: {
type: Boolean,
default: false,
},
// //
volume: { volume: {
type: Number, type: Number,
@ -92,39 +74,28 @@ const props = defineProps({
}, },
// //
listMaxHeight: { listMaxHeight: {
type: String, type: Number,
default: "420px", default: 420,
}, },
}); });
const listHeight = computed(() => {
return props.listMaxHeight + "px";
});
// //
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
try { try {
getPlayerList(props.songServer, props.songType, props.songId).then((res) => { getPlayerList(props.songServer, props.songType, props.songId).then((res) => {
console.log(res); console.log(res);
//
playIndex.value = Math.floor(Math.random() * res.length);
playListCount.value = res.length;
// //
store.musicIsOk = true; store.musicIsOk = true;
// //
res.forEach((v) => { playList.value = res;
playList.value.push({ console.log("音乐加载完成");
title: v.name || v.title, console.log(playList.value);
artist: v.artist || v.author, console.log(playIndex.value, playList.value.length, props.volume);
src: v.url || v.src,
pic: v.pic,
lrc: v.lrc,
});
});
console.log(
"音乐加载完成",
playList.value,
playIndex.value,
playListCount.value,
props.volume,
);
}); });
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -144,10 +115,11 @@ onMounted(() => {
// //
const onPlay = () => { const onPlay = () => {
console.log("播放"); console.log("播放");
playIndex.value = player.value.aplayer.index;
// //
store.setPlayerState(player.value.audio.paused); store.setPlayerState(player.value.audioRef.paused);
// //
store.setPlayerData(player.value.currentMusic.title, player.value.currentMusic.artist); store.setPlayerData(playList.value[playIndex.value].name, playList.value[playIndex.value].artist);
ElMessage({ ElMessage({
message: store.getPlayerData.name + " - " + store.getPlayerData.artist, message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
grouping: true, grouping: true,
@ -160,19 +132,23 @@ const onPlay = () => {
// //
const onPause = () => { const onPause = () => {
store.setPlayerState(player.value.audio.paused); store.setPlayerState(player.value.audioRef.paused);
}; };
// //
const onTimeUp = () => { const onTimeUp = () => {
let playerRef = player.value.$.vnode.el; let lyrics = player.value.aplayer.lyrics[playIndex.value];
if (playerRef) { let lyricIndex = player.value.aplayer.lyricIndex;
const currentLrcElement = playerRef.querySelector(".aplayer-lrc-current"); if (!lyrics || !lyrics[lyricIndex]) {
const previousLrcElement = currentLrcElement?.previousElementSibling; return;
const lrcContent =
currentLrcElement?.innerHTML || previousLrcElement?.innerHTML || "这句没有歌词";
store.setPlayerLrc(lrcContent);
} }
let lrc = lyrics[lyricIndex][1];
if (lrc === "Loading") {
lrc = "歌词加载中";
} else if (lrc === "Not available") {
lrc = "歌词加载失败";
}
store.setPlayerLrc(lrc);
}; };
// //
@ -182,41 +158,27 @@ const playToggle = () => {
// //
const changeVolume = (value) => { const changeVolume = (value) => {
player.value.audio.volume = value; player.value.setVolume(value, false);
};
const onSelectSong = (val) => {
console.log(val);
}; };
// //
const changeSong = (type) => { const changeSong = (type) => {
playIndex.value = player.value.playIndex; type === 0 ? player.value.skipBack() : player.value.skipForward();
playIndex.value += type ? 1 : -1;
// /
if (playIndex.value < 0) {
playIndex.value = playListCount.value - 1;
} else if (playIndex.value >= playListCount.value) {
playIndex.value = 0;
}
// console.log(playIndex.value, playList.value[playIndex.value]);
nextTick(() => { nextTick(() => {
player.value.play(); player.value.play();
}); });
}; };
//
const toggleList = () => {
player.value.toggleList();
};
// //
const loadMusicError = () => { const loadMusicError = () => {
let notice = ""; let notice = "";
if (playList.value.length > 1) { if (playList.value.length > 1) {
notice = "播放歌曲出现错误,播放器将在 2s 后进行下一首"; notice = "播放歌曲出现错误,播放器将在 2s 后进行下一首";
//
skipTimeout.value = setTimeout(() => {
changeSong(1);
if (!player.value.audio.paused) {
onPlay();
}
}, 2000);
} else { } else {
notice = "播放歌曲出现错误"; notice = "播放歌曲出现错误";
} }
@ -229,24 +191,22 @@ const loadMusicError = () => {
duration: 2000, duration: 2000,
}), }),
}); });
console.error("播放歌曲: " + player.value.currentMusic.title + " 出现错误"); console.error(
"播放歌曲: " + player.value.aplayer.audio[player.value.aplayer.index].name + " 出现错误",
);
}; };
// //
defineExpose({ playToggle, changeVolume, changeSong }); defineExpose({ playToggle, changeVolume, changeSong, toggleList });
onBeforeUnmount(() => {
clearTimeout(skipTimeout.value);
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.aplayer { .aplayer {
width: 80%; width: 80%;
background: transparent;
border-radius: 6px; border-radius: 6px;
font-family: "HarmonyOS_Regular", sans-serif !important; font-family: "HarmonyOS_Regular", sans-serif !important;
:deep(.aplayer-body) { :deep(.aplayer-body) {
background-color: transparent;
.aplayer-pic { .aplayer-pic {
display: none; display: none;
} }
@ -268,8 +228,8 @@ onBeforeUnmount(() => {
} }
.aplayer-lrc { .aplayer-lrc {
text-align: left; text-align: left;
margin: 4px 0 6px 6px; margin: 7px 0 6px 6px;
height: 100%; height: 44px;
mask: linear-gradient( mask: linear-gradient(
#fff 15%, #fff 15%,
#fff 85%, #fff 85%,
@ -301,6 +261,8 @@ onBeforeUnmount(() => {
} }
:deep(.aplayer-list) { :deep(.aplayer-list) {
margin-top: 6px; margin-top: 6px;
height: v-bind(listHeight);
background-color: transparent;
ol { ol {
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background-color: transparent; background-color: transparent;

View File

@ -50,7 +50,34 @@
</div> </div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item title="播放器配置" name="3"> <el-collapse-item title="播放器配置" name="3">
<div>设置内容待增加</div> <div class="item">
<span class="text">自动播放</span>
<el-switch
v-model="playerAutoplay"
inline-prompt
:active-icon="CheckSmall"
:inactive-icon="CloseSmall"
/>
</div>
<div class="item">
<span class="text">随机播放</span>
<el-switch
v-model="playerOrder"
inline-prompt
:active-icon="CheckSmall"
:inactive-icon="CloseSmall"
active-value="random"
inactive-value="list"
/>
</div>
<div class="item">
<span class="text">循环模式</span>
<el-radio-group v-model="playerLoop" size="small" text-color="#FFFFFF">
<el-radio label="all" border>列表</el-radio>
<el-radio label="one" border>单曲</el-radio>
<el-radio label="none" border>不循环</el-radio>
</el-radio-group>
</div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item title="其他设置" name="4"> <el-collapse-item title="其他设置" name="4">
<div>设置内容待增加</div> <div>设置内容待增加</div>
@ -65,7 +92,16 @@ import { mainStore } from "@/store";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
const store = mainStore(); const store = mainStore();
const { coverType, siteStartShow, musicClick, playerLrcShow, footerBlur } = storeToRefs(store); const {
coverType,
siteStartShow,
musicClick,
playerLrcShow,
footerBlur,
playerAutoplay,
playerOrder,
playerLoop,
} = storeToRefs(store);
// //
const activeName = ref("1"); const activeName = ref("1");
@ -107,13 +143,23 @@ const radioChange = () => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap;
font-size: 14px; font-size: 14px;
.el-switch__core { .el-switch__core {
border-color: transparent; border-color: transparent;
background-color: #ffffff30; background-color: #ffffff30;
} }
.el-radio-group {
.el-radio {
margin: 2px 10px 2px 0;
border-radius: 5px;
&:last-child {
margin-right: 0;
}
}
}
} }
.bg-set {
.el-radio-group { .el-radio-group {
justify-content: space-between; justify-content: space-between;
@ -153,5 +199,4 @@ const radioChange = () => {
} }
} }
} }
}
</style> </style>

View File

@ -22,6 +22,9 @@ export const mainStore = defineStore("main", {
playerLrc: "歌词加载中", // 当前播放歌词 playerLrc: "歌词加载中", // 当前播放歌词
playerLrcShow: true, // 是否显示底栏歌词 playerLrcShow: true, // 是否显示底栏歌词
footerBlur: true, // 底栏模糊 footerBlur: true, // 底栏模糊
playerAutoplay: false, // 是否自动播放
playerLoop: "all", // 循环播放 "all", "one", "none"
playerOrder: "list", // 循环顺序 "list", "random"
}; };
}, },
getters: { getters: {
@ -82,6 +85,9 @@ export const mainStore = defineStore("main", {
"musicClick", "musicClick",
"playerLrcShow", "playerLrcShow",
"footerBlur", "footerBlur",
"playerAutoplay",
"playerLoop",
"playerOrder",
], ],
}, },
}); });