mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-24 08:07:23 +08:00
🦄 refactor(MusicList): 重构播放列表组件
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<n-drawer :show="show" height="70vh" placement="bottom" :drawer-style="{ backgroundColor: 'transparent' }">
|
||||||
|
<div class="music-page">
|
||||||
|
<i class="iconfont icon-icon_error music-close" @click="close"></i>
|
||||||
|
<div class="music-title">{{ musicList?.name }}</div>
|
||||||
|
<!-- 歌单歌曲列表 -->
|
||||||
|
<div class="music-list">
|
||||||
|
<n-scrollbar >
|
||||||
|
<div v-for="(item, index) in musicList?.tracks" :key="item.id" :class="setAnimationClass('animate__bounceInUp')"
|
||||||
|
:style="setAnimationDelay(index, 100)">
|
||||||
|
<SongItem :item="formatDetail(item)" @play="handlePlay" />
|
||||||
|
</div>
|
||||||
|
<PlayBottom/>
|
||||||
|
</n-scrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</n-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { Playlist } from '@/type/listDetail';
|
||||||
|
import { setAnimationClass, setAnimationDelay } from "@/utils";
|
||||||
|
import SongItem from "@/components/common/SongItem.vue";
|
||||||
|
import PlayBottom from './common/PlayBottom.vue';
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
show: boolean;
|
||||||
|
musicList: Playlist;
|
||||||
|
}>()
|
||||||
|
const emit = defineEmits(['update:show'])
|
||||||
|
|
||||||
|
const formatDetail = computed(() => (detail: any) => {
|
||||||
|
let song = {
|
||||||
|
artists: detail.ar,
|
||||||
|
name: detail.al.name,
|
||||||
|
id: detail.al.id,
|
||||||
|
}
|
||||||
|
|
||||||
|
detail.song = song
|
||||||
|
detail.picUrl = detail.al.picUrl
|
||||||
|
return detail
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlePlay = (item: any) => {
|
||||||
|
const tracks = props.musicList?.tracks || []
|
||||||
|
const musicIndex = (tracks.findIndex((music: any) => music.id == item.id) || 0)
|
||||||
|
store.commit('setPlayList', tracks.slice(musicIndex))
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit('update:show', false)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.music {
|
||||||
|
&-page {
|
||||||
|
@apply px-8 w-full h-full bg-black bg-opacity-75 rounded-t-2xl;
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
&-title {
|
||||||
|
@apply text-lg font-bold text-white p-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-close {
|
||||||
|
@apply absolute top-4 right-8 cursor-pointer text-white text-3xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-list {
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bottom" v-if="isPlay"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
const store = useStore()
|
||||||
|
const isPlay = computed(() => store.state.isPlay as boolean)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bottom{
|
||||||
|
@apply h-28;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -67,9 +67,8 @@ const menus = store.state.menus;
|
|||||||
@apply pr-6 flex-1 box-border;
|
@apply pr-6 flex-1 box-border;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
&-content {
|
&-content {
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl pb-28 box-border;
|
||||||
height: calc(100vh - 60px);
|
height: calc(100vh - 60px);
|
||||||
margin-bottom: 90px;
|
|
||||||
}
|
}
|
||||||
&-page {
|
&-page {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
|
|||||||
+203
-203
@@ -1,203 +1,203 @@
|
|||||||
export interface IListDetail {
|
export interface IListDetail {
|
||||||
code: number;
|
code: number;
|
||||||
relatedVideos?: any;
|
relatedVideos?: any;
|
||||||
playlist: Playlist;
|
playlist: Playlist;
|
||||||
urls?: any;
|
urls?: any;
|
||||||
privileges: Privilege[];
|
privileges: Privilege[];
|
||||||
sharedPrivilege?: any;
|
sharedPrivilege?: any;
|
||||||
resEntrance?: any;
|
resEntrance?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Privilege {
|
interface Privilege {
|
||||||
id: number;
|
id: number;
|
||||||
fee: number;
|
fee: number;
|
||||||
payed: number;
|
payed: number;
|
||||||
realPayed: number;
|
realPayed: number;
|
||||||
st: number;
|
st: number;
|
||||||
pl: number;
|
pl: number;
|
||||||
dl: number;
|
dl: number;
|
||||||
sp: number;
|
sp: number;
|
||||||
cp: number;
|
cp: number;
|
||||||
subp: number;
|
subp: number;
|
||||||
cs: boolean;
|
cs: boolean;
|
||||||
maxbr: number;
|
maxbr: number;
|
||||||
fl: number;
|
fl: number;
|
||||||
pc?: any;
|
pc?: any;
|
||||||
toast: boolean;
|
toast: boolean;
|
||||||
flag: number;
|
flag: number;
|
||||||
paidBigBang: boolean;
|
paidBigBang: boolean;
|
||||||
preSell: boolean;
|
preSell: boolean;
|
||||||
playMaxbr: number;
|
playMaxbr: number;
|
||||||
downloadMaxbr: number;
|
downloadMaxbr: number;
|
||||||
rscl?: any;
|
rscl?: any;
|
||||||
freeTrialPrivilege: FreeTrialPrivilege;
|
freeTrialPrivilege: FreeTrialPrivilege;
|
||||||
chargeInfoList: ChargeInfoList[];
|
chargeInfoList: ChargeInfoList[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChargeInfoList {
|
interface ChargeInfoList {
|
||||||
rate: number;
|
rate: number;
|
||||||
chargeUrl?: any;
|
chargeUrl?: any;
|
||||||
chargeMessage?: any;
|
chargeMessage?: any;
|
||||||
chargeType: number;
|
chargeType: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FreeTrialPrivilege {
|
interface FreeTrialPrivilege {
|
||||||
resConsumable: boolean;
|
resConsumable: boolean;
|
||||||
userConsumable: boolean;
|
userConsumable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Playlist {
|
export interface Playlist {
|
||||||
id: number;
|
id: number
|
||||||
name: string;
|
name: string
|
||||||
coverImgId: number;
|
coverImgId: number
|
||||||
coverImgUrl: string;
|
coverImgUrl: string
|
||||||
coverImgId_str: string;
|
coverImgId_str: string
|
||||||
adType: number;
|
adType: number
|
||||||
userId: number;
|
userId: number
|
||||||
createTime: number;
|
createTime: number
|
||||||
status: number;
|
status: number
|
||||||
opRecommend: boolean;
|
opRecommend: boolean
|
||||||
highQuality: boolean;
|
highQuality: boolean
|
||||||
newImported: boolean;
|
newImported: boolean
|
||||||
updateTime: number;
|
updateTime: number
|
||||||
trackCount: number;
|
trackCount: number
|
||||||
specialType: number;
|
specialType: number
|
||||||
privacy: number;
|
privacy: number
|
||||||
trackUpdateTime: number;
|
trackUpdateTime: number
|
||||||
commentThreadId: string;
|
commentThreadId: string
|
||||||
playCount: number;
|
playCount: number
|
||||||
trackNumberUpdateTime: number;
|
trackNumberUpdateTime: number
|
||||||
subscribedCount: number;
|
subscribedCount: number
|
||||||
cloudTrackCount: number;
|
cloudTrackCount: number
|
||||||
ordered: boolean;
|
ordered: boolean
|
||||||
description: string;
|
description: string
|
||||||
tags: string[];
|
tags: string[]
|
||||||
updateFrequency?: any;
|
updateFrequency?: any
|
||||||
backgroundCoverId: number;
|
backgroundCoverId: number
|
||||||
backgroundCoverUrl?: any;
|
backgroundCoverUrl?: any
|
||||||
titleImage: number;
|
titleImage: number
|
||||||
titleImageUrl?: any;
|
titleImageUrl?: any
|
||||||
englishTitle?: any;
|
englishTitle?: any
|
||||||
officialPlaylistType?: any;
|
officialPlaylistType?: any
|
||||||
subscribers: Subscriber[];
|
subscribers: Subscriber[]
|
||||||
subscribed: boolean;
|
subscribed: boolean
|
||||||
creator: Subscriber;
|
creator: Subscriber
|
||||||
tracks: Track[];
|
tracks: Track[]
|
||||||
videoIds?: any;
|
videoIds?: any
|
||||||
videos?: any;
|
videos?: any
|
||||||
trackIds: TrackId[];
|
trackIds: TrackId[]
|
||||||
shareCount: number;
|
shareCount: number
|
||||||
commentCount: number;
|
commentCount: number
|
||||||
remixVideo?: any;
|
remixVideo?: any
|
||||||
sharedUsers?: any;
|
sharedUsers?: any
|
||||||
historySharedUsers?: any;
|
historySharedUsers?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TrackId {
|
interface TrackId {
|
||||||
id: number;
|
id: number;
|
||||||
v: number;
|
v: number;
|
||||||
t: number;
|
t: number;
|
||||||
at: number;
|
at: number;
|
||||||
alg?: any;
|
alg?: any;
|
||||||
uid: number;
|
uid: number;
|
||||||
rcmdReason: string;
|
rcmdReason: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Track {
|
interface Track {
|
||||||
name: string;
|
name: string;
|
||||||
id: number;
|
id: number;
|
||||||
pst: number;
|
pst: number;
|
||||||
t: number;
|
t: number;
|
||||||
ar: Ar[];
|
ar: Ar[];
|
||||||
alia: string[];
|
alia: string[];
|
||||||
pop: number;
|
pop: number;
|
||||||
st: number;
|
st: number;
|
||||||
rt?: string;
|
rt?: string;
|
||||||
fee: number;
|
fee: number;
|
||||||
v: number;
|
v: number;
|
||||||
crbt?: any;
|
crbt?: any;
|
||||||
cf: string;
|
cf: string;
|
||||||
al: Al;
|
al: Al;
|
||||||
dt: number;
|
dt: number;
|
||||||
h: H;
|
h: H;
|
||||||
m: H;
|
m: H;
|
||||||
l?: H;
|
l?: H;
|
||||||
a?: any;
|
a?: any;
|
||||||
cd: string;
|
cd: string;
|
||||||
no: number;
|
no: number;
|
||||||
rtUrl?: any;
|
rtUrl?: any;
|
||||||
ftype: number;
|
ftype: number;
|
||||||
rtUrls: any[];
|
rtUrls: any[];
|
||||||
djId: number;
|
djId: number;
|
||||||
copyright: number;
|
copyright: number;
|
||||||
s_id: number;
|
s_id: number;
|
||||||
mark: number;
|
mark: number;
|
||||||
originCoverType: number;
|
originCoverType: number;
|
||||||
originSongSimpleData?: any;
|
originSongSimpleData?: any;
|
||||||
single: number;
|
single: number;
|
||||||
noCopyrightRcmd?: any;
|
noCopyrightRcmd?: any;
|
||||||
mst: number;
|
mst: number;
|
||||||
cp: number;
|
cp: number;
|
||||||
mv: number;
|
mv: number;
|
||||||
rtype: number;
|
rtype: number;
|
||||||
rurl?: any;
|
rurl?: any;
|
||||||
publishTime: number;
|
publishTime: number;
|
||||||
tns?: string[];
|
tns?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface H {
|
interface H {
|
||||||
br: number;
|
br: number;
|
||||||
fid: number;
|
fid: number;
|
||||||
size: number;
|
size: number;
|
||||||
vd: number;
|
vd: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Al {
|
interface Al {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
picUrl: string;
|
picUrl: string;
|
||||||
tns: any[];
|
tns: any[];
|
||||||
pic_str?: string;
|
pic_str?: string;
|
||||||
pic: number;
|
pic: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Ar {
|
interface Ar {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
tns: any[];
|
tns: any[];
|
||||||
alias: any[];
|
alias: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Subscriber {
|
interface Subscriber {
|
||||||
defaultAvatar: boolean;
|
defaultAvatar: boolean;
|
||||||
province: number;
|
province: number;
|
||||||
authStatus: number;
|
authStatus: number;
|
||||||
followed: boolean;
|
followed: boolean;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
accountStatus: number;
|
accountStatus: number;
|
||||||
gender: number;
|
gender: number;
|
||||||
city: number;
|
city: number;
|
||||||
birthday: number;
|
birthday: number;
|
||||||
userId: number;
|
userId: number;
|
||||||
userType: number;
|
userType: number;
|
||||||
nickname: string;
|
nickname: string;
|
||||||
signature: string;
|
signature: string;
|
||||||
description: string;
|
description: string;
|
||||||
detailDescription: string;
|
detailDescription: string;
|
||||||
avatarImgId: number;
|
avatarImgId: number;
|
||||||
backgroundImgId: number;
|
backgroundImgId: number;
|
||||||
backgroundUrl: string;
|
backgroundUrl: string;
|
||||||
authority: number;
|
authority: number;
|
||||||
mutual: boolean;
|
mutual: boolean;
|
||||||
expertTags?: any;
|
expertTags?: any;
|
||||||
experts?: any;
|
experts?: any;
|
||||||
djStatus: number;
|
djStatus: number;
|
||||||
vipType: number;
|
vipType: number;
|
||||||
remarkName?: any;
|
remarkName?: any;
|
||||||
authenticationTypes: number;
|
authenticationTypes: number;
|
||||||
avatarDetail?: any;
|
avatarDetail?: any;
|
||||||
backgroundImgIdStr: string;
|
backgroundImgIdStr: string;
|
||||||
anchor: boolean;
|
anchor: boolean;
|
||||||
avatarImgIdStr: string;
|
avatarImgIdStr: string;
|
||||||
avatarImgId_str: string;
|
avatarImgId_str: string;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-96
@@ -1,15 +1,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getRecommendList, getListDetail, getListByTag, getListByCat } from '@/api/list'
|
import { getRecommendList, getListDetail, getListByCat } from '@/api/list'
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import type { IRecommendList, IRecommendItem } from "@/type/list";
|
import type { IRecommendItem } from "@/type/list";
|
||||||
import type { IListDetail } from "@/type/listDetail";
|
import type { IListDetail } from "@/type/listDetail";
|
||||||
import { setAnimationClass, setAnimationDelay, getImgUrl } from "@/utils";
|
import { setAnimationClass, setAnimationDelay, getImgUrl } from "@/utils";
|
||||||
import SongItem from "@/components/common/SongItem.vue";
|
import { useRoute } from 'vue-router';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import MusicList from "@/components/MusicList.vue";
|
||||||
import { useStore } from 'vuex';
|
import PlayBottom from '@/components/common/PlayBottom.vue';
|
||||||
|
|
||||||
|
|
||||||
const store = useStore();
|
|
||||||
const recommendList = ref()
|
const recommendList = ref()
|
||||||
const showMusic = ref(false)
|
const showMusic = ref(false)
|
||||||
|
|
||||||
@@ -21,9 +19,6 @@ const selectRecommendItem = async (item: IRecommendItem) => {
|
|||||||
recommendItem.value = item
|
recommendItem.value = item
|
||||||
listDetail.value = data
|
listDetail.value = data
|
||||||
}
|
}
|
||||||
const closeMusic = () => {
|
|
||||||
showMusic.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const listTitle = ref(route.query.type || "歌单列表");
|
const listTitle = ref(route.query.type || "歌单列表");
|
||||||
@@ -58,15 +53,6 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const musicFullClass = computed(() => {
|
|
||||||
if (recommendItem.value) {
|
|
||||||
return setAnimationClass('animate__fadeInUp')
|
|
||||||
} else {
|
|
||||||
return setAnimationClass('animate__fadeOutDown')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
// 格式化数字 千,万, 百万, 千万,亿
|
// 格式化数字 千,万, 百万, 千万,亿
|
||||||
const formatNumber = (num: any) => {
|
const formatNumber = (num: any) => {
|
||||||
num = num * 1
|
num = num * 1
|
||||||
@@ -78,38 +64,16 @@ const formatNumber = (num: any) => {
|
|||||||
}
|
}
|
||||||
return (num / 100000000).toFixed(1) + '亿'
|
return (num / 100000000).toFixed(1) + '亿'
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatDetail = computed(() => (detail: any) => {
|
|
||||||
let song = {
|
|
||||||
artists: detail.ar,
|
|
||||||
name: detail.al.name,
|
|
||||||
id: detail.al.id,
|
|
||||||
}
|
|
||||||
|
|
||||||
detail.song = song
|
|
||||||
detail.picUrl = detail.al.picUrl
|
|
||||||
return detail
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const handlePlay = (item: any) => {
|
|
||||||
const list = listDetail.value?.playlist.tracks || []
|
|
||||||
console.log('list',list)
|
|
||||||
console.log('item',item)
|
|
||||||
const musicIndex = (list.findIndex((music: any) => music.id == item.id) || 0)
|
|
||||||
store.commit('setPlayList', list.slice(musicIndex))
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="list-page">
|
<div class="list-page">
|
||||||
<!-- 歌单列表 -->
|
<div
|
||||||
<n-scrollbar class="recommend" @click="showMusic = false" :size="100">
|
|
||||||
<div
|
|
||||||
class="recommend-title"
|
class="recommend-title"
|
||||||
:class="setAnimationClass('animate__bounceInLeft')"
|
:class="setAnimationClass('animate__bounceInLeft')"
|
||||||
>{{ listTitle }}</div>
|
>{{ listTitle }}</div>
|
||||||
|
<!-- 歌单列表 -->
|
||||||
|
<n-scrollbar class="recommend" @click="showMusic = false" :size="100">
|
||||||
<div class="recommend-list" v-if="recommendList">
|
<div class="recommend-list" v-if="recommendList">
|
||||||
<div
|
<div
|
||||||
class="recommend-item"
|
class="recommend-item"
|
||||||
@@ -133,25 +97,9 @@ const handlePlay = (item: any) => {
|
|||||||
<div class="recommend-item-title">{{ item.name }}</div>
|
<div class="recommend-item-title">{{ item.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<PlayBottom/>
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
|
<MusicList v-if="listDetail?.playlist" v-model:show="showMusic" :music-list="listDetail?.playlist" />
|
||||||
<transition name="musicPage">
|
|
||||||
<div class="music-page" v-if="showMusic">
|
|
||||||
<i class="iconfont icon-icon_error music-close" @click="closeMusic()"></i>
|
|
||||||
<div class="music-title">{{ recommendItem?.name }}</div>
|
|
||||||
<!-- 歌单歌曲列表 -->
|
|
||||||
<n-layout class="music-list" :native-scrollbar="false">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in listDetail?.playlist.tracks"
|
|
||||||
:key="item.id"
|
|
||||||
:class="setAnimationClass('animate__bounceInUp')"
|
|
||||||
:style="setAnimationDelay(index, 50)"
|
|
||||||
>
|
|
||||||
<SongItem :item="formatDetail(item)" @play="handlePlay" />
|
|
||||||
</div>
|
|
||||||
</n-layout>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -160,14 +108,6 @@ const handlePlay = (item: any) => {
|
|||||||
@apply relative h-full w-full pt-4;
|
@apply relative h-full w-full pt-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.musicPage-enter-active {
|
|
||||||
animation: fadeInUp 0.8s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.musicPage-leave-active {
|
|
||||||
animation: fadeOutDown 0.8s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.recommend {
|
.recommend {
|
||||||
@apply w-full h-full bg-none;
|
@apply w-full h-full bg-none;
|
||||||
&-title {
|
&-title {
|
||||||
@@ -218,29 +158,4 @@ const handlePlay = (item: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.music {
|
|
||||||
&-page {
|
|
||||||
// width: 100%;
|
|
||||||
// height: 70%;
|
|
||||||
// position: absolute;
|
|
||||||
// background-color: #000000f0;
|
|
||||||
// bottom: 0;
|
|
||||||
// left: 0;
|
|
||||||
// border-radius: 30px 30px 0 0;
|
|
||||||
// animation-duration: 300ms;
|
|
||||||
@apply w-full h-5/6 absolute bottom-0 left-0 bg-black rounded-t-3xl flex flex-col transition-all;
|
|
||||||
}
|
|
||||||
&-title {
|
|
||||||
@apply text-lg font-bold text-white p-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-close {
|
|
||||||
@apply absolute top-4 right-4 cursor-pointer text-white text-3xl;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-list {
|
|
||||||
height: 594px;
|
|
||||||
background-color: #00000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@@ -7,13 +7,12 @@ import { computed, ref } from "vue";
|
|||||||
import { setAnimationClass, setAnimationDelay, getImgUrl } from "@/utils";
|
import { setAnimationClass, setAnimationDelay, getImgUrl } from "@/utils";
|
||||||
import { getListDetail } from '@/api/list'
|
import { getListDetail } from '@/api/list'
|
||||||
import SongItem from "@/components/common/SongItem.vue";
|
import SongItem from "@/components/common/SongItem.vue";
|
||||||
|
import MusicList from "@/components/MusicList.vue";
|
||||||
|
import type { Playlist } from '@/type/listDetail';
|
||||||
|
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
|
||||||
const userDetail = ref<IUserDetail>()
|
const userDetail = ref<IUserDetail>()
|
||||||
const playList = ref<any[]>([])
|
const playList = ref<any[]>([])
|
||||||
const recordList = ref()
|
const recordList = ref()
|
||||||
@@ -40,7 +39,7 @@ loadPage()
|
|||||||
|
|
||||||
|
|
||||||
const isShowList = ref(false)
|
const isShowList = ref(false)
|
||||||
const list = ref()
|
const list = ref<Playlist>()
|
||||||
// 展示歌单
|
// 展示歌单
|
||||||
const showPlaylist = async (id: number) => {
|
const showPlaylist = async (id: number) => {
|
||||||
const { data } = await getListDetail(id)
|
const { data } = await getListDetail(id)
|
||||||
@@ -61,21 +60,12 @@ const formatDetail = computed(() => (detail: any) => {
|
|||||||
return detail
|
return detail
|
||||||
})
|
})
|
||||||
|
|
||||||
const musicFullClass = computed(() => {
|
|
||||||
if (isShowList.value) {
|
|
||||||
return setAnimationClass('animate__fadeInUp')
|
|
||||||
} else {
|
|
||||||
return setAnimationClass('animate__fadeOutDown')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const handlePlay = (item: any) => {
|
const handlePlay = (item: any) => {
|
||||||
const tracks = list.value?.tracks || []
|
const tracks = recordList.value || []
|
||||||
const musicIndex = (tracks.findIndex((music: any) => music.id == item.id) || 0)
|
const musicIndex = (tracks.findIndex((music: any) => music.id == item.id) || 0)
|
||||||
store.commit('setPlayList', tracks.slice(musicIndex))
|
store.commit('setPlayList', tracks.slice(musicIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -139,28 +129,12 @@ const handlePlay = (item: any) => {
|
|||||||
:class="setAnimationClass('animate__bounceInUp')"
|
:class="setAnimationClass('animate__bounceInUp')"
|
||||||
:style="setAnimationDelay(index, 50)"
|
:style="setAnimationDelay(index, 50)"
|
||||||
>
|
>
|
||||||
<SongItem class="song-item" :item="formatDetail(item.song)" />
|
<SongItem class="song-item" :item="formatDetail(item.song)" @play="handlePlay"/>
|
||||||
<div class="play-count">{{ item.playCount }}次</div>
|
<div class="play-count">{{ item.playCount }}次</div>
|
||||||
</div>
|
</div>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
</div>
|
</div>
|
||||||
<transition name="musicPage">
|
<MusicList v-if="list" v-model:show="isShowList" :music-list="list" />
|
||||||
<div class="music-page" v-if="isShowList">
|
|
||||||
<i class="iconfont icon-icon_error music-close" @click="isShowList = false"></i>
|
|
||||||
<div class="music-title">{{ list?.name }}</div>
|
|
||||||
<!-- 歌单歌曲列表 -->
|
|
||||||
<n-layout class="music-list" :native-scrollbar="false">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in list?.tracks"
|
|
||||||
:key="item.id"
|
|
||||||
:class="setAnimationClass('animate__bounceInUp')"
|
|
||||||
:style="setAnimationDelay(index, 100)"
|
|
||||||
>
|
|
||||||
<SongItem :item="formatDetail(item)" @play="handlePlay"/>
|
|
||||||
</div>
|
|
||||||
</n-layout>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -173,7 +147,7 @@ const handlePlay = (item: any) => {
|
|||||||
animation: fadeOutDown 0.8s ease-in-out;
|
animation: fadeOutDown 0.8s ease-in-out;
|
||||||
}
|
}
|
||||||
.user-page {
|
.user-page {
|
||||||
@apply flex;
|
@apply flex h-full;
|
||||||
.left {
|
.left {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
background-color: #0d0d0d;
|
background-color: #0d0d0d;
|
||||||
@@ -204,9 +178,8 @@ const handlePlay = (item: any) => {
|
|||||||
.right {
|
.right {
|
||||||
@apply flex-1 ml-4;
|
@apply flex-1 ml-4;
|
||||||
.record-list {
|
.record-list {
|
||||||
height: 750px;
|
|
||||||
background-color: #0d0d0d;
|
background-color: #0d0d0d;
|
||||||
@apply rounded-2xl;
|
@apply rounded-2xl h-full;
|
||||||
.record-item {
|
.record-item {
|
||||||
@apply flex items-center px-4;
|
@apply flex items-center px-4;
|
||||||
}
|
}
|
||||||
@@ -247,28 +220,4 @@ const handlePlay = (item: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.music {
|
|
||||||
&-page {
|
|
||||||
width: 100%;
|
|
||||||
height: 734px;
|
|
||||||
position: absolute;
|
|
||||||
background-color: #000000f0;
|
|
||||||
top: 100px;
|
|
||||||
left: 0;
|
|
||||||
border-radius: 30px 30px 0 0;
|
|
||||||
animation-duration: 300ms;
|
|
||||||
}
|
|
||||||
&-title {
|
|
||||||
@apply text-lg font-bold text-white p-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-close {
|
|
||||||
@apply absolute top-4 right-4 cursor-pointer text-white text-3xl;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-list {
|
|
||||||
height: 594px;
|
|
||||||
background-color: #00000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user