feat: 优化搜索功能

This commit is contained in:
alger
2024-05-22 19:20:57 +08:00
parent 73982f0e84
commit a2af0f3904
6 changed files with 150 additions and 39 deletions
+1
View File
@@ -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']
+70
View File
@@ -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>
+29 -7
View File
@@ -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
View File
@@ -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,
}, // },
]; ];
+9 -8
View File
@@ -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) => {
+17
View File
@@ -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;