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
components.d.ts vendored
View File

@@ -29,6 +29,7 @@ declare module 'vue' {
PlayBottom: typeof import('./src/components/common/PlayBottom.vue')['default']
PlayListsItem: typeof import('./src/components/common/PlayListsItem.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']
RecommendSinger: typeof import('./src/components/RecommendSinger.vue')['default']
RecommendSonglist: typeof import('./src/components/RecommendSonglist.vue')['default']

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>

View File

@@ -1,19 +1,27 @@
<template>
<div class="search-item" @click="handleClick">
<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 class="search-item-info">
<div class="search-item-name">{{ item.name }}</div>
<div class="search-item-artist">{{ item.desc }}</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>
</template>
<script setup lang="ts">
import { getAlbum } from '@/api/list';
import { getAlbum, getListDetail } from '@/api/list';
import { getMvUrl } from '@/api/mv';
import { getImgUrl } from '@/utils';
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 () => {
showMusic.value = true;
if (props.item.type === '专辑') {
showPop.value = true;
const res = await getAlbum(props.item.id);
songList.value = res.data.songs.map((song: any) => {
song.al.picUrl = song.al.picUrl || props.item.picUrl;
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>
<style scoped lang="scss">
.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;
.search-item-img {
@apply w-12 h-12 mr-4 rounded-2xl overflow-hidden;

View File

@@ -30,36 +30,36 @@ export const SEARCH_TYPES = [
label: '专辑',
key: 10,
},
{
label: '歌手',
key: 100,
},
// {
// label: '歌手',
// key: 100,
// },
{
label: '歌单',
key: 1000,
},
{
label: '用户',
key: 1002,
},
// {
// label: '用户',
// key: 1002,
// },
{
label: 'MV',
key: 1004,
},
{
label: '歌词',
key: 1006,
},
{
label: '电台',
key: 1009,
},
{
label: '视频',
key: 1014,
},
{
label: '综合',
key: 1018,
},
// {
// label: '歌词',
// key: 1006,
// },
// {
// label: '电台',
// key: 1009,
// },
// {
// label: '视频',
// key: 1014,
// },
// {
// label: '综合',
// key: 1018,
// },
];

View File

@@ -95,15 +95,16 @@ const search = () => {
const { value } = searchValue;
if (value === '') {
searchValue.value = hotSearchValue.value;
} else {
router.push({
path: '/search',
query: {
keyword: value,
type: searchType.value,
},
});
return;
}
router.push({
path: '/search',
query: {
keyword: value,
type: searchType.value,
},
});
};
const selectSearchType = (key: number) => {

View File

@@ -106,6 +106,21 @@ const loadSearch = async (keywords: any) => {
const songs = data.result.songs || [];
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.forEach((item: any) => {
@@ -119,6 +134,8 @@ const loadSearch = async (keywords: any) => {
searchDetail.value = {
songs,
albums,
mvs,
playlists,
};
searchDetailLoading.value = false;