mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-24 16:27:23 +08:00
✨ feat: 优化样式,添加播放列表
This commit is contained in:
@@ -1,18 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="recommend-music-list-item">
|
<div class="song-item" :class="{'song-mini': mini}">
|
||||||
<n-image
|
<n-image
|
||||||
:src="getImgUrl( item.picUrl, '40y40')"
|
:src="getImgUrl( item.picUrl, '40y40')"
|
||||||
class="recommend-music-list-item-img"
|
class="song-item-img"
|
||||||
lazy
|
lazy
|
||||||
preview-disabled
|
preview-disabled
|
||||||
/>
|
/>
|
||||||
<div class="recommend-music-list-item-content">
|
<div class="song-item-content">
|
||||||
<div class="recommend-music-list-item-content-title">
|
<div class="song-item-content-title">
|
||||||
<n-ellipsis class="text-ellipsis" line-clamp="1">{{
|
<n-ellipsis class="text-ellipsis" line-clamp="1">{{
|
||||||
item.name
|
item.name
|
||||||
}}</n-ellipsis>
|
}}</n-ellipsis>
|
||||||
</div>
|
</div>
|
||||||
<div class="recommend-music-list-item-content-name">
|
<div class="song-item-content-name">
|
||||||
<n-ellipsis class="text-ellipsis" line-clamp="1">
|
<n-ellipsis class="text-ellipsis" line-clamp="1">
|
||||||
<span
|
<span
|
||||||
v-for="(artists, artistsindex) in item.song.artists"
|
v-for="(artists, artistsindex) in item.song.artists"
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
</n-ellipsis>
|
</n-ellipsis>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="recommend-music-list-item-operating">
|
<div class="song-item-operating">
|
||||||
<div class="recommend-music-list-item-operating-like">
|
<div class="song-item-operating-like">
|
||||||
<i class="iconfont icon-likefill"></i>
|
<i class="iconfont icon-likefill"></i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="recommend-music-list-item-operating-play bg-black"
|
class="song-item-operating-play bg-black"
|
||||||
:class="isPlaying ? 'bg-green-600' : ''"
|
:class="isPlaying ? 'bg-green-600' : ''"
|
||||||
@click="playMusicEvent(item)"
|
@click="playMusicEvent(item)"
|
||||||
>
|
>
|
||||||
@@ -44,14 +44,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import type { SongResult } from '@/type/music'
|
import type { SongResult } from '@/type/music'
|
||||||
import { computed } from 'vue'
|
|
||||||
import { getImgUrl } from '@/utils'
|
import { getImgUrl } from '@/utils'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = withDefaults(defineProps<{
|
||||||
item: {
|
item: SongResult
|
||||||
type: Object,
|
mini?: boolean
|
||||||
required: true,
|
}>(), {
|
||||||
},
|
mini: false
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@@ -77,10 +76,16 @@ const playMusicEvent = (item: any) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
// 配置文字不可选中
|
||||||
.text-ellipsis {
|
.text-ellipsis {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.recommend-music-list-item {
|
.song-item {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
@apply rounded-3xl p-3 flex items-center hover:bg-gray-800 transition;
|
@apply rounded-3xl p-3 flex items-center hover:bg-gray-800 transition;
|
||||||
&-img {
|
&-img {
|
||||||
@apply w-12 h-12 rounded-2xl mr-4;
|
@apply w-12 h-12 rounded-2xl mr-4;
|
||||||
@@ -96,7 +101,7 @@ const playMusicEvent = (item: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&-operating {
|
&-operating {
|
||||||
@apply flex items-center pl-4 rounded-full border border-gray-700;
|
@apply flex items-center pl-4 rounded-full border border-gray-700 ml-4;
|
||||||
background-color: #0d0d0d;
|
background-color: #0d0d0d;
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@apply text-xl;
|
@apply text-xl;
|
||||||
@@ -113,4 +118,35 @@ const playMusicEvent = (item: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song-mini{
|
||||||
|
@apply p-2 rounded-2xl;
|
||||||
|
.song-item{
|
||||||
|
@apply p-0;
|
||||||
|
&-img{
|
||||||
|
@apply w-10 h-10 mr-2;
|
||||||
|
}
|
||||||
|
&-content{
|
||||||
|
@apply flex-1;
|
||||||
|
&-title{
|
||||||
|
@apply text-sm;
|
||||||
|
}
|
||||||
|
&-name{
|
||||||
|
@apply text-xs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-operating{
|
||||||
|
@apply pl-2;
|
||||||
|
.iconfont{
|
||||||
|
@apply text-base;
|
||||||
|
}
|
||||||
|
&-like{
|
||||||
|
@apply mr-1;
|
||||||
|
}
|
||||||
|
&-play{
|
||||||
|
@apply w-8 h-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="app-menu">
|
<div class="app-menu">
|
||||||
<div class="app-menu-header">
|
<div class="app-menu-header">
|
||||||
<div class="app-menu-logo">
|
<div class="app-menu-logo">
|
||||||
<img src="@/assets/logo.png" class="w-9 h-9 mt-2" alt="logo" />
|
<img src="/icon.png" class="w-9 h-9" alt="logo" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-menu-list">
|
<div class="app-menu-list">
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, watch } from "@vue/runtime-core";
|
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isText: {
|
isText: {
|
||||||
@@ -67,7 +66,7 @@ const iconStyle = (index: any) => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.app-menu {
|
.app-menu {
|
||||||
@apply flex-col items-center justify-center p-6;
|
@apply flex-col items-center justify-center px-6;
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
}
|
}
|
||||||
.app-menu-item-link,
|
.app-menu-item-link,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
:drawer-style="{ backgroundColor: 'transparent' }"
|
:drawer-style="{ backgroundColor: 'transparent' }"
|
||||||
>
|
>
|
||||||
<div id="drawer-target">
|
<div id="drawer-target">
|
||||||
<div class="drawer-back" :style="{backgroundImage:`url(${getImgUrl(playMusic?.picUrl, '300y300')})`}"></div>
|
<div class="drawer-back" :class="{'paused': !isPlaying}" :style="{backgroundImage:`url(${getImgUrl(playMusic?.picUrl, '300y300')})`}"></div>
|
||||||
<div class="music-img">
|
<div class="music-img">
|
||||||
<n-image
|
<n-image
|
||||||
ref="PicImgRef"
|
ref="PicImgRef"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<n-layout
|
<n-layout
|
||||||
class="music-lrc"
|
class="music-lrc"
|
||||||
style="height: 550px"
|
style="height: 55vh"
|
||||||
ref="lrcSider"
|
ref="lrcSider"
|
||||||
:native-scrollbar="false"
|
:native-scrollbar="false"
|
||||||
@mouseover="mouseOverLayout"
|
@mouseover="mouseOverLayout"
|
||||||
@@ -43,9 +43,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
<!-- 时间矫正 -->
|
<!-- 时间矫正 -->
|
||||||
<div class="music-content-time"></div>
|
<div class="music-content-time">
|
||||||
<n-button @click="reduceCorrectionTime(0.2)">-0.2</n-button>
|
<n-button @click="reduceCorrectionTime(0.2)">-</n-button>
|
||||||
<n-button @click="addCorrectionTime(0.2)">+0.2</n-button>
|
<n-button @click="addCorrectionTime(0.2)">+</n-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</n-drawer>
|
</n-drawer>
|
||||||
@@ -54,7 +55,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SongResult } from '@/type/music'
|
import type { SongResult } from '@/type/music'
|
||||||
import { getImgUrl } from '@/utils'
|
import { getImgUrl } from '@/utils'
|
||||||
import { computed, ref } from 'vue'
|
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import {
|
import {
|
||||||
lrcArray,
|
lrcArray,
|
||||||
@@ -83,6 +83,7 @@ const emit = defineEmits(['update:musicFull'])
|
|||||||
|
|
||||||
// 播放的音乐信息
|
// 播放的音乐信息
|
||||||
const playMusic = computed(() => store.state.playMusic as SongResult)
|
const playMusic = computed(() => store.state.playMusic as SongResult)
|
||||||
|
const isPlaying = computed(() => store.state.play as boolean)
|
||||||
// 获取歌词滚动dom
|
// 获取歌词滚动dom
|
||||||
const lrcSider = ref<any>(null)
|
const lrcSider = ref<any>(null)
|
||||||
const isMouse = ref(false)
|
const isMouse = ref(false)
|
||||||
@@ -128,6 +129,10 @@ defineExpose({
|
|||||||
animation: round 20s linear infinite;
|
animation: round 20s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drawer-back.paused {
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
|
||||||
#drawer-target {
|
#drawer-target {
|
||||||
@apply top-0 left-0 absolute w-full h-full overflow-hidden rounded px-24 pt-24 pb-48 flex items-center;
|
@apply top-0 left-0 absolute w-full h-full overflow-hidden rounded px-24 pt-24 pb-48 flex items-center;
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
@@ -156,6 +161,11 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.music-content-time{
|
||||||
|
display: none;
|
||||||
|
@apply flex justify-center items-center;
|
||||||
|
}
|
||||||
|
|
||||||
.music-lrc {
|
.music-lrc {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
|
|||||||
@@ -56,24 +56,42 @@
|
|||||||
></n-slider>
|
></n-slider>
|
||||||
</div>
|
</div>
|
||||||
<div class="audio-button">
|
<div class="audio-button">
|
||||||
<n-tooltip trigger="hover">
|
<!-- <n-tooltip trigger="hover" :z-index="9999999">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<i class="iconfont icon-likefill"></i>
|
<i class="iconfont icon-likefill"></i>
|
||||||
</template>
|
</template>
|
||||||
喜欢
|
喜欢
|
||||||
</n-tooltip>
|
</n-tooltip> -->
|
||||||
<!-- <n-tooltip trigger="hover">
|
<!-- <n-tooltip trigger="hover" :z-index="9999999">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<i class="iconfont icon-Play" @click="parsingMusic"></i>
|
<i class="iconfont icon-Play" @click="parsingMusic"></i>
|
||||||
</template>
|
</template>
|
||||||
解析播放
|
解析播放
|
||||||
</n-tooltip> -->
|
</n-tooltip> -->
|
||||||
<n-tooltip trigger="hover">
|
<!-- <n-tooltip trigger="hover" :z-index="9999999">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<i class="iconfont icon-full" @click="setMusicFull"></i>
|
<i class="iconfont icon-full" @click="setMusicFull"></i>
|
||||||
</template>
|
</template>
|
||||||
歌词
|
歌词
|
||||||
</n-tooltip>
|
</n-tooltip> -->
|
||||||
|
<n-popover trigger="click" :z-index="99999999" content-class="music-play" raw :show-arrow="false" :delay="200">
|
||||||
|
<template #trigger>
|
||||||
|
<n-tooltip trigger="manual" :z-index="9999999">
|
||||||
|
<template #trigger>
|
||||||
|
<i class="iconfont icon-list"></i>
|
||||||
|
</template>
|
||||||
|
播放列表
|
||||||
|
</n-tooltip>
|
||||||
|
</template>
|
||||||
|
<div class="music-play-list">
|
||||||
|
<div class="music-play-list-back"></div>
|
||||||
|
<n-scrollbar>
|
||||||
|
<div class="music-play-list-content">
|
||||||
|
<song-item v-for="(item, index) in playList" :key="item.id" :item="item" mini></song-item>
|
||||||
|
</div>
|
||||||
|
</n-scrollbar>
|
||||||
|
</div>
|
||||||
|
</n-popover>
|
||||||
</div>
|
</div>
|
||||||
<!-- 播放音乐 -->
|
<!-- 播放音乐 -->
|
||||||
|
|
||||||
@@ -83,7 +101,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { SongResult } from '@/type/music'
|
import type { SongResult } from '@/type/music'
|
||||||
import { secondToMinute, getImgUrl } from '@/utils'
|
import { secondToMinute, getImgUrl } from '@/utils'
|
||||||
import { computed, onMounted, ref, watch } from 'vue'
|
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { setAnimationClass } from '@/utils'
|
import { setAnimationClass } from '@/utils'
|
||||||
import {
|
import {
|
||||||
@@ -92,6 +109,7 @@ import {
|
|||||||
allTime
|
allTime
|
||||||
} from '@/hooks/MusicHook'
|
} from '@/hooks/MusicHook'
|
||||||
import MusicFull from './MusicFull.vue'
|
import MusicFull from './MusicFull.vue'
|
||||||
|
import SongItem from '@/components/common/SongItem.vue'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
@@ -100,6 +118,8 @@ const playMusic = computed(() => store.state.playMusic as SongResult)
|
|||||||
// 是否播放
|
// 是否播放
|
||||||
const play = computed(() => store.state.play as boolean)
|
const play = computed(() => store.state.play as boolean)
|
||||||
|
|
||||||
|
const playList = computed(() => store.state.playList as SongResult[])
|
||||||
|
|
||||||
const audio = {
|
const audio = {
|
||||||
value: document.querySelector('#MusicAudio') as HTMLAudioElement
|
value: document.querySelector('#MusicAudio') as HTMLAudioElement
|
||||||
}
|
}
|
||||||
@@ -248,13 +268,6 @@ const setMusicFull = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.musicPage-enter-active {
|
|
||||||
animation: fadeInUp 0.4s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.musicPage-leave-active {
|
|
||||||
animation: fadeOutDown 0.4s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-ellipsis {
|
.text-ellipsis {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -262,11 +275,10 @@ const setMusicFull = () => {
|
|||||||
|
|
||||||
.music-play-bar {
|
.music-play-bar {
|
||||||
@apply h-20 w-full absolute bottom-0 left-0 flex items-center rounded-t-2xl overflow-hidden box-border px-6 py-2;
|
@apply h-20 w-full absolute bottom-0 left-0 flex items-center rounded-t-2xl overflow-hidden box-border px-6 py-2;
|
||||||
z-index: 99999999;
|
z-index: 9999;
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
background-color: rgba(0, 0, 0, 0.747);
|
box-shadow: 0px 0px 8px 0px rgba(203, 203, 203, 0.238);
|
||||||
|
background-color: rgba(0, 0, 0, 0.747); .music-content {
|
||||||
.music-content {
|
|
||||||
width: 140px;
|
width: 140px;
|
||||||
@apply ml-4;
|
@apply ml-4;
|
||||||
|
|
||||||
@@ -332,4 +344,19 @@ const setMusicFull = () => {
|
|||||||
@apply text-2xl hover:text-green-500 transition cursor-pointer m-4;
|
@apply text-2xl hover:text-green-500 transition cursor-pointer m-4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.music-play{
|
||||||
|
|
||||||
|
&-list{
|
||||||
|
height: 50vh;
|
||||||
|
@apply relative rounded-3xl overflow-hidden;
|
||||||
|
&-back{
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
@apply absolute top-0 left-0 w-full h-full bg-gray-800 bg-opacity-75;
|
||||||
|
}
|
||||||
|
&-content{
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="search-box flex">
|
<div class="search-box flex">
|
||||||
<div class="search-box-input flex-1">
|
<div class="search-box-input flex-1">
|
||||||
<n-input
|
<n-input
|
||||||
size="large"
|
size="medium"
|
||||||
round
|
round
|
||||||
v-model:value="searchValue"
|
v-model:value="searchValue"
|
||||||
:placeholder="hotSearchKeyword"
|
:placeholder="hotSearchKeyword"
|
||||||
@@ -21,14 +21,14 @@
|
|||||||
<n-avatar
|
<n-avatar
|
||||||
class="ml-2 cursor-pointer"
|
class="ml-2 cursor-pointer"
|
||||||
circle
|
circle
|
||||||
size="large"
|
size="medium"
|
||||||
:src="getImgUrl(store.state.user.avatarUrl)"
|
:src="getImgUrl(store.state.user.avatarUrl)"
|
||||||
v-if="store.state.user"
|
v-if="store.state.user"
|
||||||
/>
|
/>
|
||||||
<n-avatar
|
<n-avatar
|
||||||
class="ml-2 cursor-pointer"
|
class="ml-2 cursor-pointer"
|
||||||
circle
|
circle
|
||||||
size="large"
|
size="medium"
|
||||||
src="https://picsum.photos/200/300?random=1"
|
src="https://picsum.photos/200/300?random=1"
|
||||||
@click="toLogin()"
|
@click="toLogin()"
|
||||||
v-else
|
v-else
|
||||||
@@ -40,7 +40,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getSearchKeyword, getHotSearch } from '@/api/home';
|
import { getSearchKeyword, getHotSearch } from '@/api/home';
|
||||||
import { getUserDetail, logout } from '@/api/login';
|
import { getUserDetail, logout } from '@/api/login';
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from 'vuex';
|
import { useStore } from 'vuex';
|
||||||
import request from '@/utils/request_mt'
|
import request from '@/utils/request_mt'
|
||||||
@@ -157,7 +156,7 @@ const selectItem = async (key: any) => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.user-box {
|
.user-box {
|
||||||
@apply ml-6 flex text-lg justify-center items-center rounded-full pl-3 border border-gray-600;
|
@apply ml-4 flex text-lg justify-center items-center rounded-full pl-3 border border-gray-600;
|
||||||
background: #1a1a1a;
|
background: #1a1a1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const drag = (event: HTMLElement) => {
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
#title-bar {
|
#title-bar {
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
@apply flex justify-between text-white px-6 py-3 select-none relative;
|
@apply flex justify-between text-white px-6 py-2 select-none relative;
|
||||||
z-index: 9999999;
|
z-index: 9999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user