This commit is contained in:
底层用户 2022-11-17 14:13:03 +08:00
parent af659fe259
commit 700b53e79d
15 changed files with 1696 additions and 934 deletions

View File

@ -10,10 +10,12 @@
},
"dependencies": {
"@icon-park/vue-next": "^1.4.2",
"aplayer": "^1.10.1",
"axios": "^1.1.3",
"element-plus": "^2.2.18",
"pinia": "^2.0.23",
"vue": "^3.2.37"
"vue": "^3.2.37",
"vue3-aplayer": "^1.7.3"
},
"devDependencies": {
"@vicons/fa": "^0.12.0",

View File

@ -35,6 +35,7 @@ onMounted(() => {
//
window.addEventListener("load", () => {
console.log("加载完成");
console.clear();
//
document.getElementsByTagName("body")[0].className = "";
//

View File

@ -0,0 +1,275 @@
<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"
@play="onPlay"
@pause="onPause"
@timeupdate="onTimeUp"
/>
</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: true,
},
//
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 - 1;
//
store.musicIsOk = true;
console.log("音乐加载完成");
//
res.forEach((v) => {
playList.value.push({
title: v.name,
artist: v.artist,
src: v.url,
pic: v.pic,
lrc: v.lrc,
});
});
})
.catch(() => {
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;
playerLrc.value = playerRef.getElementsByClassName(
"aplayer-lrc-current"
)[0].innerHTML;
};
//
const playToggle = () => {
player.value.toggle();
};
//
const changeVolume = (value) => {
player.value.audio.volume = value;
};
//
const changeSong = (type) => {
if (type) {
console.log("下一曲");
playIndex.value < playListCount.value
? playIndex.value++
: (playIndex.value = 0);
} else {
console.log("上一曲");
console.log(playIndex.value);
playIndex.value > 0
? playIndex.value--
: (playIndex.value = playListCount.value);
}
console.log(playList.value[playIndex.value]);
nextTick(() => {
player.value.play();
});
};
//
defineExpose({ playToggle, changeVolume, changeSong });
//
watch(
() => playerLrc.value,
(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

@ -4,8 +4,8 @@
<script setup>
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
import "@/utils/Aplayer/APlayer.min.js";
import "@/utils/Aplayer/APlayer.min.css";
import APlayer from "APlayer";
import "APlayer/dist/APlayer.min.css";
import {
h,
ref,

View File

@ -92,7 +92,7 @@
fill="#ffffff60"
@click="musicListShow = false"
/>
<AplayerDom
<APlayerDom
:songServer="playerData.server"
:songType="playerData.type"
:songId="playerData.id"
@ -116,7 +116,7 @@ import {
VolumeSmall,
VolumeNotice,
} from "@icon-park/vue-next";
import AplayerDom from "@/components/AplayerDom/index.vue";
import APlayerDom from "@/components/APlayerDom/index.vue";
import { mainStore } from "@/store";
const store = mainStore();

View File

@ -0,0 +1,334 @@
<template>
<!-- 音乐控制面板 -->
<div
class="music"
@mouseenter="volumeShow = true"
@mouseleave="volumeShow = false"
v-show="store.musicOpenState"
>
<div class="btns">
<span @click="musicListShow = true">音乐列表</span>
<span @click="store.musicOpenState = false">回到一言</span>
</div>
<div class="control">
<go-start
theme="filled"
size="30"
fill="#efefef"
@click="changeMusicIndex(0)"
/>
<div class="state" @click="changePlayState">
<play-one
theme="filled"
size="50"
fill="#efefef"
v-show="!store.playerState"
/>
<pause
theme="filled"
size="50"
fill="#efefef"
v-show="store.playerState"
/>
</div>
<go-end
theme="filled"
size="30"
fill="#efefef"
@click="changeMusicIndex(1)"
/>
</div>
<div class="menu">
<Transition name="fade">
<div class="name" v-show="!volumeShow">
<span>{{
store.getPlayerData.name
? store.getPlayerData.name + " - " + store.getPlayerData.artist
: "未播放音乐"
}}</span>
</div>
</Transition>
<Transition name="fade">
<div class="volume" v-show="volumeShow">
<div class="icon">
<volume-mute
theme="filled"
size="24"
fill="#efefef"
v-if="volumeNum == 0"
/>
<volume-small
theme="filled"
size="24"
fill="#efefef"
v-else-if="volumeNum > 0 && volumeNum < 0.7"
/>
<volume-notice theme="filled" size="24" fill="#efefef" v-else />
</div>
<el-slider
v-model="volumeNum"
:show-tooltip="false"
:min="0"
:max="1"
:step="0.01"
/>
</div>
</Transition>
</div>
</div>
<!-- 音乐列表弹窗 -->
<Transition name="fade">
<div
class="music-list"
v-show="musicListShow"
@click="musicListShow = false"
>
<Transition name="zoom">
<div class="list" v-show="musicListShow" @click.stop>
<close-one
class="close"
theme="filled"
size="28"
fill="#ffffff60"
@click="musicListShow = false"
/>
<APlayerDom
:songServer="playerData.server"
:songType="playerData.type"
:songId="playerData.id"
:volume="volumeNum"
ref="playerRef"
/>
</div>
</Transition>
</div>
</Transition>
</template>
<script setup>
import { ref, reactive, watch, onMounted } from "vue";
import {
GoStart,
PlayOne,
Pause,
GoEnd,
CloseOne,
VolumeMute,
VolumeSmall,
VolumeNotice,
} from "@icon-park/vue-next";
import APlayerDom from "@/components/APlayerDom/index.vue";
import { mainStore } from "@/store";
const store = mainStore();
//
let volumeShow = ref(false);
let volumeNum = ref(
localStorage.getItem("aplayer-volume")
? JSON.parse(localStorage.getItem("aplayer-volume"))
: 0.7
);
//
let musicListShow = ref(false);
const playerRef = ref(null);
const musicDialog = ref(null);
const playerData = reactive({
server: import.meta.env.VITE_SONG_SERVER,
type: import.meta.env.VITE_SONG_TYPE,
id: import.meta.env.VITE_SONG_ID,
});
//
const changePlayState = () => {
playerRef.value.playToggle();
};
//
const changeMusicIndex = (type) => {
playerRef.value.changeSong(type);
};
onMounted(() => {
//
window.addEventListener("keydown", (e) => {
if (e.code == "Space") {
changePlayState();
}
});
});
//
watch(
() => volumeNum.value,
(value) => {
console.log(value);
localStorage.setItem("aplayer-volume", value);
playerRef.value.changeVolume(value);
}
);
</script>
<style lang="scss" scoped>
.music {
width: 100%;
height: 100%;
background: #00000040;
backdrop-filter: blur(10px);
border-radius: 6px;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
animation: fade;
-webkit-animation: fade 0.5s;
.btns {
display: flex;
align-items: center;
margin-bottom: 6px;
span {
background: #ffffff26;
padding: 2px 8px;
border-radius: 6px;
margin: 0px 6px;
text-overflow: ellipsis;
overflow-x: hidden;
white-space: nowrap;
&:hover {
background: #ffffff4d;
}
}
}
.control {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-evenly;
width: 100%;
.state {
.i-icon {
width: 50px;
height: 50px;
display: block;
}
}
.i-icon {
width: 36px;
height: 36px;
display: flex;
border-radius: 6px;
align-items: center;
justify-content: center;
border-radius: 6px;
transform: scale(1);
&:hover {
background: #ffffff33;
}
&:active {
transform: scale(0.95);
}
}
}
.menu {
height: 26px;
width: 100%;
line-height: 26px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.name {
width: 100%;
text-align: center;
text-overflow: ellipsis;
overflow-x: hidden;
white-space: nowrap;
// font-size: 1.1rem;
}
.volume {
width: 100%;
padding: 0 12px;
display: flex;
align-items: center;
flex-direction: row;
.icon {
margin-right: 12px;
span {
width: 24px;
height: 24px;
display: block;
}
}
:deep(*) {
transition: none;
}
:deep(.el-slider__button) {
transition: 0.3s;
}
.el-slider {
margin-right: 12px;
--el-slider-main-bg-color: #efefef;
--el-slider-runway-bg-color: #ffffff40;
--el-slider-button-size: 16px;
}
}
}
}
.music-list {
position: fixed;
top: 0;
left: 0;
margin: auto;
width: 100%;
height: 100%;
background-color: #00000080;
backdrop-filter: blur(20px);
z-index: 1;
.list {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: calc(50% - 300px);
left: calc(50% - 320px);
width: 640px;
height: 600px;
background-color: #ffffff66;
border-radius: 6px;
z-index: 999;
.close {
position: absolute;
top: 12px;
right: 12px;
width: 28px;
height: 28px;
display: block;
&:hover {
transform: scale(1.2);
}
&:active {
transform: scale(0.95);
}
}
}
}
//
.zoom-enter-active {
animation: zoom 0.4s ease-in-out;
}
.zoom-leave-active {
animation: zoom 0.3s ease-in-out reverse;
}
@keyframes zoom {
0% {
opacity: 0;
transform: scale(0) translateY(-600px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}
</style>

View File

@ -10,7 +10,7 @@
<span class="sm-hidden">{{ weatherData.weather.windpower }}&nbsp;</span>
</div>
<div class="weather" v-else>
<span>天气获取失败</span>
<span>天气数据获取失败</span>
</div>
</template>

View File

@ -130,11 +130,6 @@ p {
opacity: 0;
}
&.hover {
opacity: 0.1;
transform: scale(2.5);
}
&.active {
opacity: 0.5;
transform: scale(0.5);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -48,7 +48,6 @@ class Cursor {
refresh() {
this.scr.remove();
this.cursor.classList.remove("hover");
this.cursor.classList.remove("active");
this.pos = {
curr: null,
@ -62,8 +61,6 @@ class Cursor {
}
init() {
document.onmouseover = e => this.pt.includes(e.target.outerHTML) && this.cursor.classList.add("hover");
document.onmouseout = e => this.pt.includes(e.target.outerHTML) && this.cursor.classList.remove("hover");
document.onmousemove = e => {
(this.pos.curr == null) && this.move(e.clientX - 8, e.clientY - 8);
this.pos.curr = {

View File

@ -14,6 +14,7 @@
@click="store.boxOpenState = false"
/>
</transition>
6666
</div>
</template>

View File

@ -0,0 +1,5 @@
<template>
<div class="more">
</div>
</template>

View File

@ -39,6 +39,7 @@ export default ({
],
server: {
port: "3000",
hmr: true,
},
resolve: {
alias: [{

1989
yarn.lock

File diff suppressed because it is too large Load Diff