<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" 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-setting") ? JSON.parse(localStorage.getItem("aplayer-setting")).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) => { if (type) { playerRef.value.changeSongPrev(); } else { playerRef.value.changeSongNext(); } }; onMounted(() => { // 空格键事件 window.addEventListener("keydown", (e) => { if (e.code == "Space") { changePlayState(); } }); }); // 监听音量变化 watch( () => volumeNum.value, (value) => { console.log(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>