修复播放器

This commit is contained in:
底层用户 2023-01-14 23:18:41 +08:00
parent e7beed15cd
commit 4ce5492139
6 changed files with 525 additions and 525 deletions

View File

@ -92,12 +92,10 @@
:songServer="playerData.server" :songServer="playerData.server"
:songType="playerData.type" :songType="playerData.type"
:songId="playerData.id" :songId="playerData.id"
:volume="volumeNum"
:shuffle="true"
ref="playerRef" ref="playerRef"
/> />
<div class="error" v-if="!store.musicIsOk">
<play-wrong theme="outline" size="60" />
<span>音乐播放器加载失败</span>
</div>
</div> </div>
</Transition> </Transition>
</div> </div>
@ -105,7 +103,7 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, watch, onMounted } from "vue"; import { ref, reactive, watch, onMounted, nextTick } from "vue";
import { import {
GoStart, GoStart,
PlayOne, PlayOne,
@ -115,7 +113,6 @@ import {
VolumeMute, VolumeMute,
VolumeSmall, VolumeSmall,
VolumeNotice, VolumeNotice,
PlayWrong,
} from "@icon-park/vue-next"; } from "@icon-park/vue-next";
import Player from "@/components/Player/index.vue"; import Player from "@/components/Player/index.vue";
import { mainStore } from "@/store"; import { mainStore } from "@/store";
@ -123,11 +120,7 @@ const store = mainStore();
// //
let volumeShow = ref(false); let volumeShow = ref(false);
let volumeNum = ref( let volumeNum = ref(store.musicVolume ? store.musicVolume : 0.7);
localStorage.getItem("aplayer-setting")
? JSON.parse(localStorage.getItem("aplayer-setting")).volume
: 0.7
);
// //
let musicListShow = ref(false); let musicListShow = ref(false);
@ -138,23 +131,21 @@ const playerData = reactive({
type: import.meta.env.VITE_SONG_TYPE, type: import.meta.env.VITE_SONG_TYPE,
id: import.meta.env.VITE_SONG_ID, id: import.meta.env.VITE_SONG_ID,
}); });
// //
const changePlayState = () => { const changePlayState = () => {
playerRef.value.playToggle(); playerRef.value.playToggle();
}; };
// //
const changeMusicIndex = (type) => { const changeMusicIndex = (type) => {
if (type) { playerRef.value.changeSong(type);
playerRef.value.changeSongPrev();
} else {
playerRef.value.changeSongNext();
}
}; };
onMounted(() => { onMounted(() => {
// //
window.addEventListener("keydown", (e) => { window.addEventListener("keydown", (e) => {
if (e.code == "Space" && store.musicIsOk) { if (e.code == "Space") {
changePlayState(); changePlayState();
} }
}); });
@ -164,8 +155,8 @@ onMounted(() => {
watch( watch(
() => volumeNum.value, () => volumeNum.value,
(value) => { (value) => {
console.log(value); store.musicVolume = value;
playerRef.value.changeVolume(value); playerRef.value.changeVolume(store.musicVolume);
} }
); );
</script> </script>
@ -184,12 +175,10 @@ watch(
flex-direction: column; flex-direction: column;
animation: fade; animation: fade;
-webkit-animation: fade 0.5s; -webkit-animation: fade 0.5s;
.btns { .btns {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 6px; margin-bottom: 6px;
span { span {
background: #ffffff26; background: #ffffff26;
padding: 2px 8px; padding: 2px 8px;
@ -198,20 +187,17 @@ watch(
text-overflow: ellipsis; text-overflow: ellipsis;
overflow-x: hidden; overflow-x: hidden;
white-space: nowrap; white-space: nowrap;
&:hover { &:hover {
background: #ffffff4d; background: #ffffff4d;
} }
} }
} }
.control { .control {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
width: 100%; width: 100%;
.state { .state {
.i-icon { .i-icon {
width: 50px; width: 50px;
@ -219,7 +205,6 @@ watch(
display: block; display: block;
} }
} }
.i-icon { .i-icon {
width: 36px; width: 36px;
height: 36px; height: 36px;
@ -229,17 +214,14 @@ watch(
justify-content: center; justify-content: center;
border-radius: 6px; border-radius: 6px;
transform: scale(1); transform: scale(1);
&:hover { &:hover {
background: #ffffff33; background: #ffffff33;
} }
&:active { &:active {
transform: scale(0.95); transform: scale(0.95);
} }
} }
} }
.menu { .menu {
height: 26px; height: 26px;
width: 100%; width: 100%;
@ -248,18 +230,15 @@ watch(
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.name { .name {
width: 100%; width: 100%;
text-align: center; text-align: center;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow-x: hidden; overflow-x: hidden;
white-space: nowrap; white-space: nowrap;
// font-size: 1.1rem;
animation: fade; animation: fade;
-webkit-animation: fade 0.3s; -webkit-animation: fade 0.3s;
} }
.volume { .volume {
width: 100%; width: 100%;
padding: 0 12px; padding: 0 12px;
@ -268,25 +247,20 @@ watch(
flex-direction: row; flex-direction: row;
animation: fade; animation: fade;
-webkit-animation: fade 0.3s; -webkit-animation: fade 0.3s;
.icon { .icon {
margin-right: 12px; margin-right: 12px;
span { span {
width: 24px; width: 24px;
height: 24px; height: 24px;
display: block; display: block;
} }
} }
:deep(*) { :deep(*) {
transition: none; transition: none;
} }
:deep(.el-slider__button) { :deep(.el-slider__button) {
transition: 0.3s; transition: 0.3s;
} }
.el-slider { .el-slider {
margin-right: 12px; margin-right: 12px;
--el-slider-main-bg-color: #efefef; --el-slider-main-bg-color: #efefef;
@ -296,7 +270,6 @@ watch(
} }
} }
} }
.music-list { .music-list {
position: fixed; position: fixed;
top: 0; top: 0;
@ -307,7 +280,6 @@ watch(
background-color: #00000080; background-color: #00000080;
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
z-index: 1; z-index: 1;
.list { .list {
position: absolute; position: absolute;
display: flex; display: flex;
@ -320,7 +292,6 @@ watch(
background-color: #ffffff66; background-color: #ffffff66;
border-radius: 6px; border-radius: 6px;
z-index: 999; z-index: 999;
.close { .close {
position: absolute; position: absolute;
top: 12px; top: 12px;
@ -328,33 +299,22 @@ watch(
width: 28px; width: 28px;
height: 28px; height: 28px;
display: block; display: block;
&:hover { &:hover {
transform: scale(1.2); transform: scale(1.2);
} }
&:active { &:active {
transform: scale(0.95); transform: scale(0.95);
} }
} }
.error {
display: flex;
flex-direction: column;
align-items: center;
.i-icon {
margin-bottom: 20px;
}
}
} }
} }
// //
.fade-enter-active { .fade-enter-active {
animation: fade 0.3s ease-in-out; animation: fade 0.3s ease-in-out;
} }
.fade-leave-active { .fade-leave-active {
animation: fade 0.3s ease-in-out reverse; animation: fade 0.3s ease-in-out reverse;
} }
.zoom-enter-active { .zoom-enter-active {
animation: zoom 0.4s ease-in-out; animation: zoom 0.4s ease-in-out;

View File

@ -92,10 +92,12 @@
:songServer="playerData.server" :songServer="playerData.server"
:songType="playerData.type" :songType="playerData.type"
:songId="playerData.id" :songId="playerData.id"
:volume="volumeNum"
:shuffle="true"
ref="playerRef" ref="playerRef"
/> />
<div class="error" v-if="!store.musicIsOk">
<play-wrong theme="outline" size="60" />
<span>音乐播放器加载失败</span>
</div>
</div> </div>
</Transition> </Transition>
</div> </div>
@ -103,7 +105,7 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, watch, onMounted, nextTick } from "vue"; import { ref, reactive, watch, onMounted } from "vue";
import { import {
GoStart, GoStart,
PlayOne, PlayOne,
@ -113,14 +115,19 @@ import {
VolumeMute, VolumeMute,
VolumeSmall, VolumeSmall,
VolumeNotice, VolumeNotice,
PlayWrong,
} from "@icon-park/vue-next"; } from "@icon-park/vue-next";
import Player from "@/components/Player/Beta.vue"; import Player from "@/components/Player/index.vue";
import { mainStore } from "@/store"; import { mainStore } from "@/store";
const store = mainStore(); const store = mainStore();
// //
let volumeShow = ref(false); let volumeShow = ref(false);
let volumeNum = ref(store.musicVolume ? store.musicVolume : 0.7); let volumeNum = ref(
localStorage.getItem("aplayer-setting")
? JSON.parse(localStorage.getItem("aplayer-setting")).volume
: 0.7
);
// //
let musicListShow = ref(false); let musicListShow = ref(false);
@ -131,21 +138,23 @@ const playerData = reactive({
type: import.meta.env.VITE_SONG_TYPE, type: import.meta.env.VITE_SONG_TYPE,
id: import.meta.env.VITE_SONG_ID, id: import.meta.env.VITE_SONG_ID,
}); });
// //
const changePlayState = () => { const changePlayState = () => {
playerRef.value.playToggle(); playerRef.value.playToggle();
}; };
// //
const changeMusicIndex = (type) => { const changeMusicIndex = (type) => {
playerRef.value.changeSong(type); if (type) {
playerRef.value.changeSongPrev();
} else {
playerRef.value.changeSongNext();
}
}; };
onMounted(() => { onMounted(() => {
// //
window.addEventListener("keydown", (e) => { window.addEventListener("keydown", (e) => {
if (e.code == "Space") { if (e.code == "Space" && store.musicIsOk) {
changePlayState(); changePlayState();
} }
}); });
@ -155,8 +164,8 @@ onMounted(() => {
watch( watch(
() => volumeNum.value, () => volumeNum.value,
(value) => { (value) => {
store.musicVolume = value; console.log(value);
playerRef.value.changeVolume(store.musicVolume); playerRef.value.changeVolume(value);
} }
); );
</script> </script>
@ -175,10 +184,12 @@ watch(
flex-direction: column; flex-direction: column;
animation: fade; animation: fade;
-webkit-animation: fade 0.5s; -webkit-animation: fade 0.5s;
.btns { .btns {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 6px; margin-bottom: 6px;
span { span {
background: #ffffff26; background: #ffffff26;
padding: 2px 8px; padding: 2px 8px;
@ -187,17 +198,20 @@ watch(
text-overflow: ellipsis; text-overflow: ellipsis;
overflow-x: hidden; overflow-x: hidden;
white-space: nowrap; white-space: nowrap;
&:hover { &:hover {
background: #ffffff4d; background: #ffffff4d;
} }
} }
} }
.control { .control {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
width: 100%; width: 100%;
.state { .state {
.i-icon { .i-icon {
width: 50px; width: 50px;
@ -205,6 +219,7 @@ watch(
display: block; display: block;
} }
} }
.i-icon { .i-icon {
width: 36px; width: 36px;
height: 36px; height: 36px;
@ -214,14 +229,17 @@ watch(
justify-content: center; justify-content: center;
border-radius: 6px; border-radius: 6px;
transform: scale(1); transform: scale(1);
&:hover { &:hover {
background: #ffffff33; background: #ffffff33;
} }
&:active { &:active {
transform: scale(0.95); transform: scale(0.95);
} }
} }
} }
.menu { .menu {
height: 26px; height: 26px;
width: 100%; width: 100%;
@ -230,15 +248,18 @@ watch(
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.name { .name {
width: 100%; width: 100%;
text-align: center; text-align: center;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow-x: hidden; overflow-x: hidden;
white-space: nowrap; white-space: nowrap;
// font-size: 1.1rem;
animation: fade; animation: fade;
-webkit-animation: fade 0.3s; -webkit-animation: fade 0.3s;
} }
.volume { .volume {
width: 100%; width: 100%;
padding: 0 12px; padding: 0 12px;
@ -247,20 +268,25 @@ watch(
flex-direction: row; flex-direction: row;
animation: fade; animation: fade;
-webkit-animation: fade 0.3s; -webkit-animation: fade 0.3s;
.icon { .icon {
margin-right: 12px; margin-right: 12px;
span { span {
width: 24px; width: 24px;
height: 24px; height: 24px;
display: block; display: block;
} }
} }
:deep(*) { :deep(*) {
transition: none; transition: none;
} }
:deep(.el-slider__button) { :deep(.el-slider__button) {
transition: 0.3s; transition: 0.3s;
} }
.el-slider { .el-slider {
margin-right: 12px; margin-right: 12px;
--el-slider-main-bg-color: #efefef; --el-slider-main-bg-color: #efefef;
@ -270,6 +296,7 @@ watch(
} }
} }
} }
.music-list { .music-list {
position: fixed; position: fixed;
top: 0; top: 0;
@ -280,6 +307,7 @@ watch(
background-color: #00000080; background-color: #00000080;
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
z-index: 1; z-index: 1;
.list { .list {
position: absolute; position: absolute;
display: flex; display: flex;
@ -292,6 +320,7 @@ watch(
background-color: #ffffff66; background-color: #ffffff66;
border-radius: 6px; border-radius: 6px;
z-index: 999; z-index: 999;
.close { .close {
position: absolute; position: absolute;
top: 12px; top: 12px;
@ -299,22 +328,33 @@ watch(
width: 28px; width: 28px;
height: 28px; height: 28px;
display: block; display: block;
&:hover { &:hover {
transform: scale(1.2); transform: scale(1.2);
} }
&:active { &:active {
transform: scale(0.95); transform: scale(0.95);
} }
} }
.error {
display: flex;
flex-direction: column;
align-items: center;
.i-icon {
margin-bottom: 20px;
}
}
} }
} }
// //
.fade-enter-active { .fade-enter-active {
animation: fade 0.3s ease-in-out; animation: fade 0.3s ease-in-out;
} }
.fade-leave-active { .fade-leave-active {
animation: fade 0.3s ease-in-out reverse; animation: fade 0.3s ease-in-out reverse;
} }
.zoom-enter-active { .zoom-enter-active {
animation: zoom 0.4s ease-in-out; animation: zoom 0.4s ease-in-out;

View File

@ -1,306 +0,0 @@
<template>
<aplayer
showLrc
ref="player"
v-if="playList[0]"
:music="playList[playIndex]"
:list="playList"
:autoplay="autoplay"
:theme="theme"
:repeat="repeat"
:shuffle="shuffle"
:listMaxHeight="listMaxHeight"
:listFolded="listFolded"
:volume="volume"
@play="onPlay"
@pause="onPause"
@timeupdate="onTimeUp"
@onSelectSong="onSelectSong"
/>
</template>
<script setup>
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
import aplayer from "vue3-aplayer";
import {
h,
ref,
reactive,
nextTick,
onMounted,
onBeforeUnmount,
watch,
} from "vue";
import { getPlayerList } from "@/api";
import { mainStore } from "@/store";
const store = mainStore();
// DOM
const player = ref(null);
//
let playList = ref([]);
let playerLrc = ref("");
//
let playIndex = ref(0);
let playListCount = ref(0);
//
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,
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",
},
//
listFolded: {
type: Boolean,
default: false,
},
//
listMaxHeight: {
type: String,
default: "420px",
},
});
//
onMounted(() => {
nextTick(() => {
getPlayerList(props.songServer, props.songType, props.songId)
.then((res) => {
//
playIndex.value = Math.floor(Math.random() * res.length);
playListCount.value = res.length;
//
store.musicIsOk = true;
console.log(
"音乐加载完成",
res,
playIndex.value,
playListCount.value,
props.volume
);
//
res.forEach((v) => {
playList.value.push({
title: v.name,
artist: v.artist,
src: v.url,
pic: v.pic,
lrc: v.lrc,
});
});
})
.catch(() => {
store.musicIsOk = false;
ElMessage({
message: "播放器加载失败",
grouping: true,
icon: h(PlayWrong, {
theme: "filled",
fill: "#efefef",
}),
});
});
});
});
//
const onPlay = () => {
console.log("播放");
//
store.setPlayerState(player.value.audio.paused);
//
store.setPlayerData(
player.value.currentMusic.title,
player.value.currentMusic.artist
);
ElMessage({
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
grouping: true,
icon: h(MusicOne, {
theme: "filled",
fill: "#efefef",
}),
});
};
const onPause = () => {
store.setPlayerState(player.value.audio.paused);
};
//
const onTimeUp = () => {
let playerRef = player.value.$.vnode.el;
if (playerRef) {
playerLrc.value = playerRef.getElementsByClassName(
"aplayer-lrc-current"
)[0].innerHTML;
store.setPlayerLrc(playerLrc.value);
}
};
//
const playToggle = () => {
player.value.toggle();
};
//
const changeVolume = (value) => {
player.value.audio.volume = value;
};
const onSelectSong = (val) => {
console.log(val);
};
//
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]);
nextTick(() => {
player.value.play();
});
};
//
defineExpose({ playToggle, changeVolume, changeSong });
</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-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: 4px 0 6px 6px;
height: 100%;
mask: linear-gradient(
180deg,
hsla(0, 0%, 100%, 0) 0,
hsla(0, 0%, 100%, 0.6) 10%,
#fff 15%,
#fff 85%,
hsla(0, 0%, 100%, 0.6) 90%,
hsla(0, 0%, 100%, 0)
);
-webkit-mask: linear-gradient(
180deg,
hsla(0, 0%, 100%, 0) 0,
hsla(0, 0%, 100%, 0.6) 10%,
#fff 15%,
#fff 85%,
hsla(0, 0%, 100%, 0.6) 90%,
hsla(0, 0%, 100%, 0)
);
&::before,
&::after {
display: none;
}
p {
color: #efefef;
margin: 2px 0;
}
.aplayer-lrc-current {
font-size: 0.95rem;
margin-bottom: 4px !important;
}
}
.aplayer-controller {
display: none;
}
}
}
:deep(.aplayer-list) {
margin-top: 6px;
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>

View File

@ -1,11 +1,27 @@
<template> <template>
<div ref="playerRef"></div> <aplayer
showLrc
ref="player"
v-if="playList[0]"
:music="playList[playIndex]"
:list="playList"
:autoplay="autoplay"
:theme="theme"
:repeat="repeat"
:shuffle="shuffle"
:listMaxHeight="listMaxHeight"
:listFolded="listFolded"
:volume="volume"
@play="onPlay"
@pause="onPause"
@timeupdate="onTimeUp"
@onSelectSong="onSelectSong"
/>
</template> </template>
<script setup> <script setup>
import { MusicOne, PlayWrong } from "@icon-park/vue-next"; import { MusicOne, PlayWrong } from "@icon-park/vue-next";
import APlayer from "APlayer"; import aplayer from "vue3-aplayer";
import "aplayer/dist/APlayer.min.css";
import { import {
h, h,
ref, ref,
@ -17,51 +33,22 @@ import {
} from "vue"; } from "vue";
import { getPlayerList } from "@/api"; import { getPlayerList } from "@/api";
import { mainStore } from "@/store"; import { mainStore } from "@/store";
const store = mainStore(); const store = mainStore();
const playerRef = ref(); // DOM
const state = reactive({ const player = ref(null);
instance: null,
});
const playerData = reactive({
name: null,
artist: null,
lrc: null,
});
// APlayer //
class Audio { let playList = ref([]);
// let playerLrc = ref("");
// artist: String;
//
// name: String;
//
// url: String;
//
// cover: String;
//
// lrc: String;
constructor(artist, name, url, cover, lrc) { //
this.artist = artist; let playIndex = ref(0);
this.name = name; let playListCount = ref(0);
this.url = url;
this.cover = cover;
this.lrc = lrc;
}
}
//
const props = defineProps({ const props = defineProps({
//
fixed: {
type: Boolean,
default: false,
},
//
mini: {
type: Boolean,
default: false,
},
// //
autoplay: { autoplay: {
type: Boolean, type: Boolean,
@ -73,19 +60,14 @@ const props = defineProps({
default: "#efefef", default: "#efefef",
}, },
// //
loop: { repeat: {
type: String, type: String,
default: "all", //'all' | 'one' | 'none' default: "list", //'list' | 'music' | 'none'
}, },
// //
order: { shuffle: {
type: String, type: Boolean,
default: "random", //'list' | 'random' default: false,
},
//
preload: {
type: String,
default: "auto", //'auto' | 'metadata' | 'none'
}, },
// //
volume: { volume: {
@ -110,16 +92,6 @@ const props = defineProps({
type: String, type: String,
default: "7452421335", default: "7452421335",
}, },
//
mutex: {
type: Boolean,
default: true,
},
//
lrcType: {
type: Number,
default: 3,
},
// //
listFolded: { listFolded: {
type: Boolean, type: Boolean,
@ -130,11 +102,6 @@ const props = defineProps({
type: String, type: String,
default: "420px", default: "420px",
}, },
// localStorage key
storageName: {
type: String,
default: "aplayer-setting",
},
}); });
// //
@ -142,67 +109,28 @@ onMounted(() => {
nextTick(() => { nextTick(() => {
getPlayerList(props.songServer, props.songType, props.songId) getPlayerList(props.songServer, props.songType, props.songId)
.then((res) => { .then((res) => {
// console.log(res); //
playIndex.value = Math.floor(Math.random() * res.length);
playListCount.value = res.length;
// //
store.musicIsOk = true; store.musicIsOk = true;
console.log("音乐加载完成"); console.log(
let audioList = res.map( "音乐加载完成",
(value) => res,
new Audio(value.artist, value.name, value.url, value.pic, value.lrc) playIndex.value,
playListCount.value,
props.volume
); );
state.instance = new APlayer({ //
container: playerRef.value, res.forEach((v) => {
fixed: props.fixed, playList.value.push({
mini: props.mini, title: v.name,
autoplay: props.autoplay, artist: v.artist,
theme: props.theme, src: v.url,
loop: props.loop, pic: v.pic,
order: props.order, lrc: v.lrc,
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(() => { .catch(() => {
store.musicIsOk = false; store.musicIsOk = false;
@ -218,41 +146,72 @@ onMounted(() => {
}); });
}); });
// //
onBeforeUnmount(() => { const onPlay = () => {
state.instance.destroy(); console.log("播放");
}); //
store.setPlayerState(player.value.audio.paused);
//
store.setPlayerData(
player.value.currentMusic.title,
player.value.currentMusic.artist
);
ElMessage({
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
grouping: true,
icon: h(MusicOne, {
theme: "filled",
fill: "#efefef",
}),
});
};
const onPause = () => {
store.setPlayerState(player.value.audio.paused);
};
//
const onTimeUp = () => {
let playerRef = player.value.$.vnode.el;
if (playerRef) {
playerLrc.value = playerRef.getElementsByClassName(
"aplayer-lrc-current"
)[0].innerHTML;
store.setPlayerLrc(playerLrc.value);
}
};
// //
const playToggle = () => { const playToggle = () => {
state.instance.toggle(); player.value.toggle();
}; };
// //
const changeVolume = (value) => { const changeVolume = (value) => {
state.instance.volume(value); player.value.audio.volume = value;
};
const onSelectSong = (val) => {
console.log(val);
}; };
// //
const changeSongPrev = () => { const changeSong = (type) => {
state.instance.skipBack(); playIndex.value = player.value.playIndex;
}; playIndex.value += type ? 1 : -1;
const changeSongNext = () => { // /
state.instance.skipForward(); 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(() => {
player.value.play();
});
}; };
// //
defineExpose({ playToggle, changeVolume, changeSongPrev, changeSongNext }); defineExpose({ playToggle, changeVolume, changeSong });
//
watch(
() => playerData.lrc,
(value) => {
console.log(value);
// pinia
store.setPlayerLrc(value);
}
);
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
@ -268,22 +227,47 @@ watch(
margin-left: 0; margin-left: 0;
background-color: #ffffff40; background-color: #ffffff40;
border-color: transparent; border-color: transparent;
.aplayer-title { .aplayer-music {
font-size: 16px; flex-grow: initial;
} margin-bottom: 2px;
.aplayer-author { overflow: initial;
color: #efefef; .aplayer-title {
font-size: 16px;
margin-right: 6px;
}
.aplayer-author {
color: #efefef;
}
} }
.aplayer-lrc { .aplayer-lrc {
text-align: left; text-align: left;
margin: 4px 0 0 6px; margin: 4px 0 6px 6px;
height: 38px; height: 100%;
mask: linear-gradient(
180deg,
hsla(0, 0%, 100%, 0) 0,
hsla(0, 0%, 100%, 0.6) 10%,
#fff 15%,
#fff 85%,
hsla(0, 0%, 100%, 0.6) 90%,
hsla(0, 0%, 100%, 0)
);
-webkit-mask: linear-gradient(
180deg,
hsla(0, 0%, 100%, 0) 0,
hsla(0, 0%, 100%, 0.6) 10%,
#fff 15%,
#fff 85%,
hsla(0, 0%, 100%, 0.6) 90%,
hsla(0, 0%, 100%, 0)
);
&::before, &::before,
&::after { &::after {
display: none; display: none;
} }
p { p {
color: #efefef; color: #efefef;
margin: 2px 0;
} }
.aplayer-lrc-current { .aplayer-lrc-current {
font-size: 0.95rem; font-size: 0.95rem;
@ -298,6 +282,9 @@ watch(
:deep(.aplayer-list) { :deep(.aplayer-list) {
margin-top: 6px; margin-top: 6px;
ol { ol {
&::-webkit-scrollbar-track{
background-color: transparent;
}
li { li {
border-color: transparent; border-color: transparent;
&.aplayer-list-light { &.aplayer-list-light {

View File

@ -0,0 +1,319 @@
<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>

View File

@ -34,7 +34,7 @@
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount } from "vue"; import { ref, onMounted, onBeforeUnmount } from "vue";
import Music from "@/components/Music/test.vue"; import Music from "@/components/Music/index.vue";
import Hitokoto from "@/components/Hitokoto/index.vue"; import Hitokoto from "@/components/Hitokoto/index.vue";
import Weather from "@/components/Weather/index.vue"; import Weather from "@/components/Weather/index.vue";
import { getCurrentTime } from "@/utils/getTime"; import { getCurrentTime } from "@/utils/getTime";