mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-30 03:47:22 +08:00
✨ feat: 优化搜索功能
This commit is contained in:
Vendored
+1
@@ -29,6 +29,7 @@ declare module 'vue' {
|
|||||||
PlayBottom: typeof import('./src/components/common/PlayBottom.vue')['default']
|
PlayBottom: typeof import('./src/components/common/PlayBottom.vue')['default']
|
||||||
PlayListsItem: typeof import('./src/components/common/PlayListsItem.vue')['default']
|
PlayListsItem: typeof import('./src/components/common/PlayListsItem.vue')['default']
|
||||||
PlaylistType: typeof import('./src/components/PlaylistType.vue')['default']
|
PlaylistType: typeof import('./src/components/PlaylistType.vue')['default']
|
||||||
|
PlayVideo: typeof import('./src/components/common/PlayVideo.vue')['default']
|
||||||
RecommendAlbum: typeof import('./src/components/RecommendAlbum.vue')['default']
|
RecommendAlbum: typeof import('./src/components/RecommendAlbum.vue')['default']
|
||||||
RecommendSinger: typeof import('./src/components/RecommendSinger.vue')['default']
|
RecommendSinger: typeof import('./src/components/RecommendSinger.vue')['default']
|
||||||
RecommendSonglist: typeof import('./src/components/RecommendSonglist.vue')['default']
|
RecommendSonglist: typeof import('./src/components/RecommendSonglist.vue')['default']
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<n-drawer :show="show" height="100vh" placement="bottom" :z-index="999999999">
|
||||||
|
<div class="mv-detail">
|
||||||
|
<video :src="url" controls autoplay></video>
|
||||||
|
<div class="mv-detail-title">
|
||||||
|
<div class="title">{{ title }}</div>
|
||||||
|
<button @click="close">
|
||||||
|
<i class="iconfont icon-xiasanjiaoxing"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</n-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
show: boolean;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.show,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
store.commit('setIsPlay', false);
|
||||||
|
store.commit('setPlayMusic', false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:show']);
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit('update:show', false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.mv-detail {
|
||||||
|
@apply w-full h-full bg-black relative;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
@apply absolute w-full left-0 flex justify-between h-16 px-6 py-2 text-xl font-bold items-center z-50 transition-all duration-300 ease-in-out -top-24;
|
||||||
|
background: linear-gradient(0, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
|
||||||
|
button .icon-xiasanjiaoxing {
|
||||||
|
@apply text-3xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
@apply text-green-400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
@apply w-full h-full;
|
||||||
|
}
|
||||||
|
video:hover + .mv-detail-title {
|
||||||
|
@apply top-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mv-detail-title:hover {
|
||||||
|
@apply top-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,19 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="search-item" @click="handleClick">
|
<div class="search-item" @click="handleClick">
|
||||||
<div class="search-item-img">
|
<div class="search-item-img">
|
||||||
<n-image :src="getImgUrl(item.picUrl, 'album')" lazy preview-disabled />
|
<n-image :src="getImgUrl(item.picUrl, '200y200')" lazy preview-disabled />
|
||||||
</div>
|
</div>
|
||||||
<div class="search-item-info">
|
<div class="search-item-info">
|
||||||
<div class="search-item-name">{{ item.name }}</div>
|
<div class="search-item-name">{{ item.name }}</div>
|
||||||
<div class="search-item-artist">{{ item.desc }}</div>
|
<div class="search-item-artist">{{ item.desc }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MusicList v-model:show="showMusic" :name="item.name" :song-list="songList" />
|
<MusicList
|
||||||
|
v-if="['专辑', 'playlist'].includes(item.type)"
|
||||||
|
v-model:show="showPop"
|
||||||
|
:name="item.name"
|
||||||
|
:song-list="songList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PlayVideo v-if="item.type === 'mv'" v-model:show="showPop" :title="item.name" :url="url" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getAlbum } from '@/api/list';
|
import { getAlbum, getListDetail } from '@/api/list';
|
||||||
|
import { getMvUrl } from '@/api/mv';
|
||||||
import { getImgUrl } from '@/utils';
|
import { getImgUrl } from '@/utils';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -26,25 +34,39 @@ const props = defineProps<{
|
|||||||
};
|
};
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const songList = ref([]);
|
const url = ref('');
|
||||||
|
|
||||||
const showMusic = ref(false);
|
const songList = ref<any[]>([]);
|
||||||
|
|
||||||
|
const showPop = ref(false);
|
||||||
|
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
showMusic.value = true;
|
|
||||||
if (props.item.type === '专辑') {
|
if (props.item.type === '专辑') {
|
||||||
|
showPop.value = true;
|
||||||
const res = await getAlbum(props.item.id);
|
const res = await getAlbum(props.item.id);
|
||||||
songList.value = res.data.songs.map((song: any) => {
|
songList.value = res.data.songs.map((song: any) => {
|
||||||
song.al.picUrl = song.al.picUrl || props.item.picUrl;
|
song.al.picUrl = song.al.picUrl || props.item.picUrl;
|
||||||
return song;
|
return song;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.item.type === 'playlist') {
|
||||||
|
showPop.value = true;
|
||||||
|
const res = await getListDetail(props.item.id);
|
||||||
|
songList.value = res.data.playlist.tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.item.type === 'mv') {
|
||||||
|
const res = await getMvUrl(props.item.id);
|
||||||
|
url.value = res.data.data.url;
|
||||||
|
showPop.value = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.search-item {
|
.search-item {
|
||||||
@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 cursor-pointer;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
.search-item-img {
|
.search-item-img {
|
||||||
@apply w-12 h-12 mr-4 rounded-2xl overflow-hidden;
|
@apply w-12 h-12 mr-4 rounded-2xl overflow-hidden;
|
||||||
|
|||||||
+24
-24
@@ -30,36 +30,36 @@ export const SEARCH_TYPES = [
|
|||||||
label: '专辑',
|
label: '专辑',
|
||||||
key: 10,
|
key: 10,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
label: '歌手',
|
// label: '歌手',
|
||||||
key: 100,
|
// key: 100,
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
label: '歌单',
|
label: '歌单',
|
||||||
key: 1000,
|
key: 1000,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
label: '用户',
|
// label: '用户',
|
||||||
key: 1002,
|
// key: 1002,
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
label: 'MV',
|
label: 'MV',
|
||||||
key: 1004,
|
key: 1004,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
label: '歌词',
|
// label: '歌词',
|
||||||
key: 1006,
|
// key: 1006,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
label: '电台',
|
// label: '电台',
|
||||||
key: 1009,
|
// key: 1009,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
label: '视频',
|
// label: '视频',
|
||||||
key: 1014,
|
// key: 1014,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
label: '综合',
|
// label: '综合',
|
||||||
key: 1018,
|
// key: 1018,
|
||||||
},
|
// },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -95,15 +95,16 @@ const search = () => {
|
|||||||
const { value } = searchValue;
|
const { value } = searchValue;
|
||||||
if (value === '') {
|
if (value === '') {
|
||||||
searchValue.value = hotSearchValue.value;
|
searchValue.value = hotSearchValue.value;
|
||||||
} else {
|
return;
|
||||||
router.push({
|
|
||||||
path: '/search',
|
|
||||||
query: {
|
|
||||||
keyword: value,
|
|
||||||
type: searchType.value,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router.push({
|
||||||
|
path: '/search',
|
||||||
|
query: {
|
||||||
|
keyword: value,
|
||||||
|
type: searchType.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectSearchType = (key: number) => {
|
const selectSearchType = (key: number) => {
|
||||||
|
|||||||
@@ -106,6 +106,21 @@ const loadSearch = async (keywords: any) => {
|
|||||||
|
|
||||||
const songs = data.result.songs || [];
|
const songs = data.result.songs || [];
|
||||||
const albums = data.result.albums || [];
|
const albums = data.result.albums || [];
|
||||||
|
const mvs = (data.result.mvs || []).map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
picUrl: item.cover,
|
||||||
|
playCount: item.playCount,
|
||||||
|
desc: item.artists.map((artist: any) => artist.name).join('/'),
|
||||||
|
type: 'mv',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const playlists = (data.result.playlists || []).map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
picUrl: item.coverImgUrl,
|
||||||
|
playCount: item.playCount,
|
||||||
|
desc: item.creator.nickname,
|
||||||
|
type: 'playlist',
|
||||||
|
}));
|
||||||
|
|
||||||
// songs map 替换属性
|
// songs map 替换属性
|
||||||
songs.forEach((item: any) => {
|
songs.forEach((item: any) => {
|
||||||
@@ -119,6 +134,8 @@ const loadSearch = async (keywords: any) => {
|
|||||||
searchDetail.value = {
|
searchDetail.value = {
|
||||||
songs,
|
songs,
|
||||||
albums,
|
albums,
|
||||||
|
mvs,
|
||||||
|
playlists,
|
||||||
};
|
};
|
||||||
|
|
||||||
searchDetailLoading.value = false;
|
searchDetailLoading.value = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user