mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-05 07:20:50 +08:00
✨ feat: 优化搜索功能
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -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']
|
||||
|
||||
70
src/components/common/PlayVideo.vue
Normal file
70
src/components/common/PlayVideo.vue
Normal 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>
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
// },
|
||||
];
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user