feat: 卡片播放按钮可直接播放 #111

This commit is contained in:
imsyy
2023-12-29 14:32:10 +08:00
parent 0cedfe0af3
commit a341a69d48
4 changed files with 162 additions and 11 deletions

7
components.d.ts vendored
View File

@@ -12,6 +12,7 @@ declare module 'vue' {
CommentList: typeof import('./src/components/List/CommentList.vue')['default']
CountDown: typeof import('./src/components/Player/CountDown.vue')['default']
CoverDropdown: typeof import('./src/components/Cover/CoverDropdown.vue')['default']
CoverPlayBtn: typeof import('./src/components/Cover/CoverPlayBtn.vue')['default']
CreatePlaylist: typeof import('./src/components/Modal/CreatePlaylist.vue')['default']
DownloadSong: typeof import('./src/components/Modal/DownloadSong.vue')['default']
FullPlayer: typeof import('./src/components/Player/FullPlayer.vue')['default']
@@ -46,7 +47,7 @@ declare module 'vue' {
NGrid: typeof import('naive-ui')['NGrid']
NH1: typeof import('naive-ui')['NH1']
NH3: typeof import('naive-ui')['NH3']
NH4: (typeof import("naive-ui"))["NH4"]
NH4: typeof import('naive-ui')['NH4']
NH6: typeof import('naive-ui')['NH6']
NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage']
@@ -63,14 +64,12 @@ declare module 'vue' {
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NNumberAnimation: (typeof import("naive-ui"))["NNumberAnimation"]
NNumberAnimation: typeof import('naive-ui')['NNumberAnimation']
NPagination: typeof import('naive-ui')['NPagination']
NPopover: typeof import('naive-ui')['NPopover']
NProgress: typeof import('naive-ui')['NProgress']
NQrCode: typeof import('naive-ui')['NQrCode']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NResult: (typeof import("naive-ui"))["NResult"]
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NSkeleton: typeof import('naive-ui')['NSkeleton']

View File

@@ -4,6 +4,7 @@
"chevron-down": "M7.41 8.58L12 13.17l4.59-4.59L18 10l-6 6l-6-6z",
"play": "M9.525 18.025q-.5.325-1.012.038T8 17.175V6.825q0-.6.513-.888t1.012.038l8.15 5.175q.45.3.45.85t-.45.85l-8.15 5.175Z",
"play-circle": "M10 16.5v-9l6 4.5M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2Z",
"pause-circle": "M15 16h-2V8h2m-4 8H9V8h2m1-6A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2",
"play-next": "m10 16.5l6-4.5l-6-4.5M22 12c0-5.54-4.46-10-10-10c-1.17 0-2.3.19-3.38.56l.7 1.94c.85-.34 1.74-.53 2.68-.53c4.41 0 8.03 3.62 8.03 8.03c0 4.41-3.62 8.03-8.03 8.03c-4.41 0-8.03-3.62-8.03-8.03c0-.94.19-1.88.53-2.72l-1.94-.66C2.19 9.7 2 10.83 2 12c0 5.54 4.46 10 10 10s10-4.46 10-10M5.47 3.97c.85 0 1.53.71 1.53 1.5C7 6.32 6.32 7 5.47 7c-.79 0-1.5-.68-1.5-1.53c0-.79.71-1.5 1.5-1.5Z",
"playlist-add": "M4 16q-.425 0-.713-.288T3 15q0-.425.288-.713T4 14h5q.425 0 .713.288T10 15q0 .425-.288.713T9 16H4Zm0-4q-.425 0-.713-.288T3 11q0-.425.288-.713T4 10h9q.425 0 .713.288T14 11q0 .425-.288.713T13 12H4Zm0-4q-.425 0-.713-.288T3 7q0-.425.288-.713T4 6h9q.425 0 .713.288T14 7q0 .425-.288.713T13 8H4Zm13 12q-.425 0-.713-.288T16 19v-3h-3q-.425 0-.713-.288T12 15q0-.425.288-.713T13 14h3v-3q0-.425.288-.713T17 10q.425 0 .713.288T18 11v3h3q.425 0 .713.288T22 15q0 .425-.288.713T21 16h-3v3q0 .425-.288.713T17 20Z",
"account-music": "M11 14c1 0 2.05.16 3.2.44c-.81.87-1.2 1.89-1.2 3.06c0 .89.25 1.73.78 2.5H3v-2c0-1.19.91-2.15 2.74-2.88C7.57 14.38 9.33 14 11 14m0-2c-1.08 0-2-.39-2.82-1.17C7.38 10.05 7 9.11 7 8c0-1.08.38-2 1.18-2.82C9 4.38 9.92 4 11 4c1.11 0 2.05.38 2.83 1.18C14.61 6 15 6.92 15 8c0 1.11-.39 2.05-1.17 2.83c-.78.78-1.72 1.17-2.83 1.17m7.5-2H22v2h-2v5.5a2.5 2.5 0 0 1-2.5 2.5a2.5 2.5 0 0 1-2.5-2.5a2.5 2.5 0 0 1 2.5-2.5c.36 0 .69.07 1 .21V10Z",

View File

@@ -0,0 +1,146 @@
<!-- 封面列表 - 播放按钮 -->
<template>
<div class="play-btn" @click.stop>
<n-button
:loading="playLoading"
color="#efefefde"
tag="div"
type="primary"
class="play"
size="large"
strong
secondary
circle
@click.stop="playAllSongs"
>
<template #icon>
<Transition name="fade" mode="out-in">
<n-icon :key="`${isHasSongs}-${playState}`" size="50">
<SvgIcon :icon="isHasSongs !== -1 && playState ? 'pause-circle' : 'play-circle'" />
</n-icon>
</Transition>
</template>
</n-button>
</div>
</template>
<script setup>
import { storeToRefs } from "pinia";
import { useRouter } from "vue-router";
import { getAllPlayList } from "@/api/playlist";
import { getAlbumDetail } from "@/api/album";
import { getDjProgram } from "@/api/dj";
import { musicData, siteStatus } from "@/stores";
import { playOrPause, initPlayer } from "@/utils/Player";
import formatData from "@/utils/formatData";
const router = useRouter();
const music = musicData();
const status = siteStatus();
const { playList, playSongData } = storeToRefs(music);
const { playIndex, playMode, playHeartbeatMode, playState } = storeToRefs(status);
const props = defineProps({
// id
id: {
type: Number,
required: true,
},
// 歌单类型
type: {
type: String,
default: "playlist",
},
});
// 播放按钮数据
const playLoading = ref(false);
const playListData = ref(null);
// 是否处于当前歌单
const isHasSongs = computed(() => {
if (!playListData.value) return -1;
const songId = music.getPlaySongData?.id;
const existingIndex = playListData.value.findIndex((song) => song.id === songId);
return existingIndex;
});
// 获取歌单数据
const getPlaylistData = async () => {
// 为了播放速度,仅加载列表前 500 首
console.log(props.type, props.id);
// 按列表类别获取数据
switch (props.type) {
case "playlist": {
const result = await getAllPlayList(props.id, 500);
return formatData(result.songs, "song");
}
case "album": {
const result = await getAlbumDetail(props.id);
return formatData(result.songs, "song");
}
case "dj": {
const result = await getDjProgram(props.id, 500);
return formatData(result.programs, "dj");
}
default:
return null;
}
};
// 播放歌单
const playAllSongs = async () => {
try {
if (!props.id) return false;
// 开启加载状态
if (props.type !== "mv") {
// 若不处于歌单内
if (isHasSongs.value === -1) {
playLoading.value = true;
// 获取歌单数据
playListData.value = await getPlaylistData();
console.log(playListData.value);
if (!playListData.value) {
playLoading.value = false;
return $message.error("获取播放列表时出现错误");
}
console.log("不在歌单内");
// 更改模式和歌单
playHeartbeatMode.value = false;
playMode.value = props.type === "dj" ? "dj" : "normal";
playList.value = playListData.value.slice();
playSongData.value = playListData.value[0];
playIndex.value = 0;
// 初始化播放器
await initPlayer(true);
playLoading.value = false;
$message.info("已开始播放", { showIcon: false });
}
// 若处于歌单内
else {
console.log("处于歌单内");
playSongData.value = playListData.value[isHasSongs.value];
playIndex.value = isHasSongs.value;
// 播放
playOrPause();
}
} else {
// 跳转播放器
router.push({
path: "/videos-player",
query: {
id: props.id,
},
});
}
} catch (error) {
console.error("获取播放列表时出现错误:", error);
$message.error("获取播放列表时出现错误");
}
};
</script>
<style lang="scss" scoped>
.play-btn {
backdrop-filter: blur(20px);
}
</style>

View File

@@ -56,8 +56,9 @@
<n-text class="add-desc">{{ item.desc }}</n-text>
</div>
<!-- 播放按钮 -->
<n-icon class="play">
<SvgIcon :icon="type !== 'artist' ? 'play-circle' : 'account-music'" />
<CoverPlayBtn v-if="type !== 'artist'" :id="item.id" :type="type" />
<n-icon v-else class="play-btn">
<SvgIcon icon="account-music" />
</n-icon>
</div>
<!-- 信息 -->
@@ -286,14 +287,18 @@ const jumpLink = (data, type) => {
-webkit-line-clamp: 2;
}
}
.play {
.play-btn {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
right: 8px;
bottom: 8px;
opacity: 0;
color: #efefefde;
transform: translateY(6px);
font-size: 50px;
border-radius: 50%;
overflow: hidden;
z-index: 3;
transition:
opacity 0.3s,
@@ -356,7 +361,7 @@ const jumpLink = (data, type) => {
top: 0;
opacity: 1;
}
.play {
.play-btn {
opacity: 1;
transform: translateY(0);
&:hover {
@@ -385,8 +390,8 @@ const jumpLink = (data, type) => {
border-radius: 50%;
overflow: hidden;
}
.play {
// display: none;
.play-btn {
font-size: 50px;
right: auto;
bottom: auto;
}