Merge pull request #229 from first19326/dev
feat: 替换 vue3-aplayer 插件,并添加播放器设置选项
This commit is contained in:
commit
e2290042f7
@ -14,6 +14,7 @@
|
||||
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@worstone/vue-aplayer": "^1.0.4",
|
||||
"aplayer": "^1.10.1",
|
||||
"axios": "^1.1.3",
|
||||
"element-plus": "^2.2.18",
|
||||
@ -21,8 +22,7 @@
|
||||
"pinia": "^2.0.23",
|
||||
"pinia-plugin-persistedstate": "^3.0.0",
|
||||
"swiper": "^9.3.2",
|
||||
"vue": "^3.3.4",
|
||||
"vue3-aplayer": "^1.7.3"
|
||||
"vue": "^3.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@icon-park/vue-next": "^1.4.2",
|
||||
|
544
pnpm-lock.yaml
544
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -22,18 +22,18 @@ export const getPlayerList = async (server, type, id) => {
|
||||
).replace("http://", "https://");
|
||||
|
||||
return data.map((v, i) => ({
|
||||
title: v.name || v.title,
|
||||
name: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
src: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
||||
pic: v.pic,
|
||||
url: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
||||
cover: v.cover || v.pic,
|
||||
lrc: v.lrc,
|
||||
}));
|
||||
} else {
|
||||
return data.map((v) => ({
|
||||
title: v.name || v.title,
|
||||
name: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
src: v.url,
|
||||
pic: v.pic,
|
||||
url: v.url,
|
||||
cover: v.cover || v.pic,
|
||||
lrc: v.lrc,
|
||||
}));
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
</div>
|
||||
<!-- 音乐列表弹窗 -->
|
||||
<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">
|
||||
<div class="list" v-show="musicListShow" @click.stop>
|
||||
<close-one
|
||||
@ -51,7 +51,7 @@
|
||||
theme="filled"
|
||||
size="28"
|
||||
fill="#ffffff60"
|
||||
@click="musicListShow = false"
|
||||
@click="closeMusicList()"
|
||||
/>
|
||||
<Player
|
||||
ref="playerRef"
|
||||
@ -59,7 +59,6 @@
|
||||
:songType="playerData.type"
|
||||
:songId="playerData.id"
|
||||
:volume="volumeNum"
|
||||
:shuffle="false"
|
||||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
@ -98,6 +97,13 @@ const playerData = reactive({
|
||||
// 开启播放列表
|
||||
const openMusicList = () => {
|
||||
musicListShow.value = true;
|
||||
playerRef.value.toggleList();
|
||||
};
|
||||
|
||||
// 关闭播放列表
|
||||
const closeMusicList = () => {
|
||||
musicListShow.value = false;
|
||||
playerRef.value.toggleList();
|
||||
};
|
||||
|
||||
// 音乐播放暂停
|
||||
|
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<aplayer
|
||||
showLrc
|
||||
ref="player"
|
||||
<APlayer
|
||||
v-if="playList[0]"
|
||||
:music="playList[playIndex]"
|
||||
:list="playList"
|
||||
:autoplay="autoplay"
|
||||
ref="player"
|
||||
:audio="playList"
|
||||
:autoplay="store.playerAutoplay"
|
||||
:theme="theme"
|
||||
:repeat="repeat"
|
||||
:shuffle="shuffle"
|
||||
:listMaxHeight="listMaxHeight"
|
||||
:listFolded="listFolded"
|
||||
:autoSwitch="false"
|
||||
:loop="store.playerLoop"
|
||||
:order="store.playerOrder"
|
||||
:volume="volume"
|
||||
:showLrc="true"
|
||||
:listFolded="listFolded"
|
||||
:listMaxHeight="listMaxHeight"
|
||||
:noticeSwitch="false"
|
||||
@play="onPlay"
|
||||
@pause="onPause"
|
||||
@timeupdate="onTimeUp"
|
||||
@onSelectSong="onSelectSong"
|
||||
@error="loadMusicError"
|
||||
/>
|
||||
</template>
|
||||
@ -24,7 +24,7 @@
|
||||
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
|
||||
import { getPlayerList } from "@/api";
|
||||
import { mainStore } from "@/store";
|
||||
import aplayer from "vue3-aplayer";
|
||||
import APlayer from "@worstone/vue-aplayer";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
@ -36,32 +36,14 @@ const playList = ref([]);
|
||||
|
||||
// 歌曲播放项
|
||||
const playIndex = ref(0);
|
||||
const playListCount = ref(0);
|
||||
|
||||
const skipTimeout = ref(null);
|
||||
|
||||
// 配置项
|
||||
const props = defineProps({
|
||||
// 音频自动播放
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 主题色
|
||||
theme: {
|
||||
type: String,
|
||||
default: "#efefef",
|
||||
},
|
||||
// 音频循环播放
|
||||
repeat: {
|
||||
type: String,
|
||||
default: "list", //'list' | 'music' | 'none'
|
||||
},
|
||||
// 随机播放
|
||||
shuffle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 默认音量
|
||||
volume: {
|
||||
type: Number,
|
||||
@ -92,39 +74,28 @@ const props = defineProps({
|
||||
},
|
||||
// 列表最大高度
|
||||
listMaxHeight: {
|
||||
type: String,
|
||||
default: "420px",
|
||||
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);
|
||||
// 生成歌单信息
|
||||
playIndex.value = Math.floor(Math.random() * res.length);
|
||||
playListCount.value = res.length;
|
||||
// 更改播放器加载状态
|
||||
store.musicIsOk = true;
|
||||
// 生成歌单
|
||||
res.forEach((v) => {
|
||||
playList.value.push({
|
||||
title: v.name || v.title,
|
||||
artist: v.artist || v.author,
|
||||
src: v.url || v.src,
|
||||
pic: v.pic,
|
||||
lrc: v.lrc,
|
||||
});
|
||||
});
|
||||
console.log(
|
||||
"音乐加载完成",
|
||||
playList.value,
|
||||
playIndex.value,
|
||||
playListCount.value,
|
||||
props.volume,
|
||||
);
|
||||
playList.value = res;
|
||||
console.log("音乐加载完成");
|
||||
console.log(playList.value);
|
||||
console.log(playIndex.value, playList.value.length, props.volume);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -144,10 +115,11 @@ onMounted(() => {
|
||||
// 播放
|
||||
const onPlay = () => {
|
||||
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({
|
||||
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
|
||||
grouping: true,
|
||||
@ -160,19 +132,23 @@ const onPlay = () => {
|
||||
|
||||
// 暂停
|
||||
const onPause = () => {
|
||||
store.setPlayerState(player.value.audio.paused);
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
};
|
||||
|
||||
// 音频时间更新事件
|
||||
const onTimeUp = () => {
|
||||
let playerRef = player.value.$.vnode.el;
|
||||
if (playerRef) {
|
||||
const currentLrcElement = playerRef.querySelector(".aplayer-lrc-current");
|
||||
const previousLrcElement = currentLrcElement?.previousElementSibling;
|
||||
const lrcContent =
|
||||
currentLrcElement?.innerHTML || previousLrcElement?.innerHTML || "这句没有歌词";
|
||||
store.setPlayerLrc(lrcContent);
|
||||
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);
|
||||
};
|
||||
|
||||
// 切换播放暂停事件
|
||||
@ -182,41 +158,27 @@ const playToggle = () => {
|
||||
|
||||
// 切换音量事件
|
||||
const changeVolume = (value) => {
|
||||
player.value.audio.volume = value;
|
||||
};
|
||||
|
||||
const onSelectSong = (val) => {
|
||||
console.log(val);
|
||||
player.value.setVolume(value, false);
|
||||
};
|
||||
|
||||
// 切换上下曲
|
||||
const changeSong = (type) => {
|
||||
playIndex.value = player.value.playIndex;
|
||||
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]);
|
||||
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 后进行下一首";
|
||||
// 播放下一首
|
||||
skipTimeout.value = setTimeout(() => {
|
||||
changeSong(1);
|
||||
if (!player.value.audio.paused) {
|
||||
onPlay();
|
||||
}
|
||||
}, 2000);
|
||||
} else {
|
||||
notice = "播放歌曲出现错误";
|
||||
}
|
||||
@ -229,24 +191,22 @@ const loadMusicError = () => {
|
||||
duration: 2000,
|
||||
}),
|
||||
});
|
||||
console.error("播放歌曲: " + player.value.currentMusic.title + " 出现错误");
|
||||
console.error(
|
||||
"播放歌曲: " + player.value.aplayer.audio[player.value.aplayer.index].name + " 出现错误",
|
||||
);
|
||||
};
|
||||
|
||||
// 暴露子组件方法
|
||||
defineExpose({ playToggle, changeVolume, changeSong });
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(skipTimeout.value);
|
||||
});
|
||||
defineExpose({ playToggle, changeVolume, changeSong, toggleList });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.aplayer {
|
||||
width: 80%;
|
||||
background: transparent;
|
||||
border-radius: 6px;
|
||||
font-family: "HarmonyOS_Regular", sans-serif !important;
|
||||
:deep(.aplayer-body) {
|
||||
background-color: transparent;
|
||||
.aplayer-pic {
|
||||
display: none;
|
||||
}
|
||||
@ -268,8 +228,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
.aplayer-lrc {
|
||||
text-align: left;
|
||||
margin: 4px 0 6px 6px;
|
||||
height: 100%;
|
||||
margin: 7px 0 6px 6px;
|
||||
height: 44px;
|
||||
mask: linear-gradient(
|
||||
#fff 15%,
|
||||
#fff 85%,
|
||||
@ -301,6 +261,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
:deep(.aplayer-list) {
|
||||
margin-top: 6px;
|
||||
height: v-bind(listHeight);
|
||||
background-color: transparent;
|
||||
ol {
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
|
@ -50,7 +50,34 @@
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<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 title="其他设置" name="4">
|
||||
<div>设置内容待增加</div>
|
||||
@ -65,7 +92,16 @@ import { mainStore } from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
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");
|
||||
@ -107,45 +143,54 @@ const radioChange = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
font-size: 14px;
|
||||
.el-switch__core {
|
||||
border-color: transparent;
|
||||
background-color: #ffffff30;
|
||||
}
|
||||
}
|
||||
.bg-set {
|
||||
.el-radio-group {
|
||||
justify-content: space-between;
|
||||
|
||||
.el-radio {
|
||||
margin: 10px 16px;
|
||||
background: #ffffff26;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 8px;
|
||||
margin: 2px 10px 2px 0;
|
||||
border-radius: 5px;
|
||||
|
||||
.el-radio__label {
|
||||
color: #fff;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-radio-group {
|
||||
justify-content: space-between;
|
||||
|
||||
.el-radio {
|
||||
margin: 10px 16px;
|
||||
background: #ffffff26;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 8px;
|
||||
|
||||
.el-radio__label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-radio__inner {
|
||||
background: #ffffff06 !important;
|
||||
border: 2px solid #eeeeee !important;
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
background: #ffffff06 !important;
|
||||
border: 2px solid #eeeeee !important;
|
||||
}
|
||||
|
||||
.is-checked {
|
||||
.el-radio__inner {
|
||||
background: #ffffff06 !important;
|
||||
border: 2px solid #eeeeee !important;
|
||||
background-color: #ffffff30 !important;
|
||||
border-color: #fff !important;
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
background: #ffffff06 !important;
|
||||
border: 2px solid #eeeeee !important;
|
||||
}
|
||||
|
||||
.is-checked {
|
||||
.el-radio__inner {
|
||||
background-color: #ffffff30 !important;
|
||||
border-color: #fff !important;
|
||||
}
|
||||
|
||||
& + .el-radio__label {
|
||||
color: #fff !important;
|
||||
}
|
||||
& + .el-radio__label {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ export const mainStore = defineStore("main", {
|
||||
playerLrc: "歌词加载中", // 当前播放歌词
|
||||
playerLrcShow: true, // 是否显示底栏歌词
|
||||
footerBlur: true, // 底栏模糊
|
||||
playerAutoplay: false, // 是否自动播放
|
||||
playerLoop: "all", // 循环播放 "all", "one", "none"
|
||||
playerOrder: "list", // 循环顺序 "list", "random"
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
@ -82,6 +85,9 @@ export const mainStore = defineStore("main", {
|
||||
"musicClick",
|
||||
"playerLrcShow",
|
||||
"footerBlur",
|
||||
"playerAutoplay",
|
||||
"playerLoop",
|
||||
"playerOrder",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user