diff --git a/src/app/my/collect/page.tsx b/src/app/my/collect/page.tsx index c201d4d..7e0f8c7 100644 --- a/src/app/my/collect/page.tsx +++ b/src/app/my/collect/page.tsx @@ -10,6 +10,7 @@ import styles from '../index.module.css'; import { SongCardList, Pagination } from '@/components'; import { apiGetSongCollect } from '@/services'; +import useAudioStore from '@/store/audio'; import useUserStore from '@/store/user'; export default function Journal() { @@ -19,6 +20,13 @@ export default function Journal() { })), ); + const { setPlayList, setAudioId } = useAudioStore( + useShallow((state) => ({ + setAudioId: state.setAudioId, + setPlayList: state.setPlayList, + })), + ); + const [type, setType] = useState<'single' | 'journal'>('single'); // 收藏类型 const [total, setTotal] = useState(0); const [pageNum, setPageNum] = useState(1); @@ -36,6 +44,13 @@ export default function Journal() { setType(type); }; + // 播放 + const handlePlay = (id: string) => { + if (!id) return; + setPlayList(list); + setAudioId(id); + }; + const getList = async () => { setLoading(true); const result = await apiGetSongCollect({ userId: userInfo?.id, pageNum: -1, pageSize: -1 }); @@ -77,11 +92,20 @@ export default function Journal() { ))} -
+ {/* 播放按钮 */} +
handlePlay(list?.[0]?.id)} + > 播放全部
{/* List */} - + {!!total && ( void; }) { - const { audioId, order, playQueue, showCard, switchSongByDiff, setOrder } = useAudioStore( + const { playState, audioId, order, playQueue, showCard, setPlayState, switchSongByDiff, setOrder } = useAudioStore( useShallow((state) => { return { + playState: state.playState, audioId: state.audioId, order: state.order, playQueue: state.playQueue, showCard: state.showCard, + setPlayState: state.setPlayState, setOrder: state.setOrder, switchSongByDiff: state.switchSongByDiff, }; @@ -35,7 +37,6 @@ export default function AudioPlayer({ const audioRef = useRef(new Audio(audio?.src || '')); const isReady = useRef(false); // 是否加载过组件 - const [isPlaying, setIsPlaying] = useState(false); // 播放状态 const [trackProgress, setTrackProgress] = useState(0); // 音频进度(s) const [duration, setDuration] = useState(0); // 音频总时长(s) @@ -49,7 +50,7 @@ export default function AudioPlayer({ // 播放/暂停 const handlePlay = () => { - setIsPlaying((isPlaying) => !isPlaying); + setPlayState(!playState); }; /** @@ -59,7 +60,7 @@ export default function AudioPlayer({ const handleSwitchAudio = (direction: number) => { if (order === 'single') { audioRef.current.currentTime = 0; - !isPlaying && setIsPlaying(true); + !playState && setPlayState(true); return; } switchSongByDiff(direction); @@ -69,7 +70,7 @@ export default function AudioPlayer({ const handleChangeProgress = (value: string) => { audioRef.current.currentTime = Number(value); setTrackProgress(audioRef.current.currentTime); - setIsPlaying(true); + setPlayState(true); }; // 监听音频进度 @@ -85,8 +86,8 @@ export default function AudioPlayer({ // 播放/暂停事件 useEffect(() => { - isPlaying ? audioRef.current.play() : audioRef.current.pause(); - }, [isPlaying]); + playState ? audioRef.current.play() : audioRef.current.pause(); + }, [playState]); // 切换歌曲 useEffect(() => { @@ -101,7 +102,7 @@ export default function AudioPlayer({ if (isReady.current) { audioRef.current.addEventListener('loadedmetadata', handleLoadedMetadata); // 获取音频时长 audioRef.current.play(); - setIsPlaying(true); + setPlayState(true); } else { isReady.current = true; } @@ -119,7 +120,7 @@ export default function AudioPlayer({ }; document.addEventListener('keydown', handleKeyDown); // 监听快捷键 - setIsPlaying(false); // 禁止自动播放 + setPlayState(false); // 禁止自动播放 return () => { audioRef.current.pause(); @@ -130,7 +131,7 @@ export default function AudioPlayer({ return ( + + + +
+ ); +} diff --git a/src/components/Icon/index.module.css b/src/components/Icon/index.module.css new file mode 100644 index 0000000..9d23816 --- /dev/null +++ b/src/components/Icon/index.module.css @@ -0,0 +1,73 @@ +.equalizer { + width: 24px; + height: 24px; + padding: 6px; + box-sizing: border-box; + display: flex; + justify-content: space-between; +} + +.equalizer span { + width: 2px; + border-radius: 4px; + background: #c43737ff; + animation: up-and-down 2s linear infinite; +} + +.equalizer span:nth-child(1) { + animation-delay: 0.4s; +} + +.equalizer span:nth-child(2) { +} + +.equalizer span:nth-child(3) { + animation-delay: 0.7s; +} + +.equalizer.paused span { + animation-play-state: paused; +} + +@keyframes up-and-down { + 0%, + 100% { + clip-path: inset(27% 0 0 0); + } + + 10% { + clip-path: inset(17% 0 0 0); + } + + 20% { + clip-path: inset(55% 0 0 0); + } + + 30% { + clip-path: inset(30% 0 0 0); + } + + 40% { + clip-path: inset(13% 0 0 0); + } + + 50% { + clip-path: inset(38% 0 0 0); + } + + 60% { + clip-path: inset(80% 0 0 0); + } + + 70% { + clip-path: inset(21% 0 0 0); + } + + 80% { + clip-path: inset(0% 0 0 0); + } + + 90% { + clip-path: inset(36% 0 0 0); + } +} diff --git a/src/components/Song/Full.tsx b/src/components/Song/Full.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/components/Song/SongCardList.tsx b/src/components/Song/SongCardList.tsx deleted file mode 100644 index 60c3f0f..0000000 --- a/src/components/Song/SongCardList.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 歌曲卡片 - */ -'use client'; - -import { useShallow } from 'zustand/react/shallow'; - -import { SongCard } from '@/components'; -import useAudioStore from '@/store/audio'; - -interface Props { - listId: string; - songList: SongInfo[]; - className?: string; -} - -export default function JournalItem({ listId, songList, className }: Props) { - const { setPlayList, setAudioId, playListId } = useAudioStore( - useShallow((state) => ({ - setAudioId: state.setAudioId, - setPlayList: state.setPlayList, - playListId: state.playListId, - })), - ); - - const handlePlayList = (id: string) => { - // 正在播放其他歌单 - if (playListId !== listId) { - setPlayList({ id: listId, list: songList }); - } - - // 正在播放当前歌单 - setAudioId(id); - }; - - return ( -
- {songList.map((song: SongInfo) => ( - handlePlayList(audioId)} /> - ))} -
- ); -} diff --git a/src/components/Song/SongCard.tsx b/src/components/SongCard/SongCard.tsx similarity index 56% rename from src/components/Song/SongCard.tsx rename to src/components/SongCard/SongCard.tsx index 0aa9e26..2278fed 100644 --- a/src/components/Song/SongCard.tsx +++ b/src/components/SongCard/SongCard.tsx @@ -1,16 +1,29 @@ import Image from 'next/image'; -import { ButtonCollect } from '@/components'; +import { ButtonCollect, Equalizer } from '@/components'; + +interface Props extends SongInfo { + /** 播放状态 */ + playState: boolean; + /** 展示收藏按钮 */ + showCollect: boolean; + /** 显示均衡器效果 */ + showEq: boolean; + onPlay: (id: string) => void; +} export default function JournalItem({ + playState, id, title, pic, artist, haveCollect, duration, + showEq, + showCollect, onPlay, -}: SongInfo & { onPlay: (id: string) => void }) { +}: Props) { return (
{/* left */}
+ {/* 专辑封面 */} {title} + {/* 歌曲名称/歌手 */}
{title}
{artist}
@@ -27,22 +42,19 @@ export default function JournalItem({ {/* right */}
- {title} - + {/* 均衡器效果 */} + {showEq && } + {/* 音频时长 */}

{duration || '00:00'}

- - + {/* 收藏按钮 */} + {showCollect && ( + + )}
); diff --git a/src/components/SongCard/SongCardList.tsx b/src/components/SongCard/SongCardList.tsx new file mode 100644 index 0000000..13a4eca --- /dev/null +++ b/src/components/SongCard/SongCardList.tsx @@ -0,0 +1,58 @@ +/** + * 歌曲卡片 + */ +'use client'; + +import { useShallow } from 'zustand/react/shallow'; + +import { SongCard } from '@/components'; +import useAudioStore from '@/store/audio'; + +interface Props { + listId: string; + songList: SongInfo[]; + className?: string; + /** 收藏按钮的显示逻辑 + * always: 总是显示 + * playing: 播放时显示 + */ + collectType?: 'always' | 'playing'; +} + +export default function JournalItem({ songList, className, collectType = 'always' }: Props) { + const { playState, audioId, setPlayState, setAudioId, setPlayList } = useAudioStore( + useShallow((state) => ({ + playState: state.playState, + audioId: state.audioId, + setPlayState: state.setPlayState, + setAudioId: state.setAudioId, + setPlayList: state.setPlayList, + })), + ); + + const handlePlayList = (id: string) => { + if (!id) return; + if (id === audioId) { + setPlayState(!playState); + return; + } + // 设置播放列表、音频id + setPlayList(songList); + setAudioId(id); + }; + + return ( +
+ {songList.map((item: SongInfo) => ( + handlePlayList(audioId)} + showCollect={collectType === 'always' || (collectType === 'playing' && item.id === audioId)} + /> + ))} +
+ ); +} diff --git a/src/components/index.ts b/src/components/index.ts index f7d0f04..254eb89 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,6 +2,9 @@ export { default as Logo } from './Logo'; export { default as Header } from './Header/index'; export { default as Footer } from './Footer'; +// Icon +export { default as Equalizer } from './Icon/Equalizer'; + // Home export { default as Category } from './Category'; export { default as ContributorCard } from './ContributorCard'; @@ -28,9 +31,9 @@ export { default as ButtonCollect } from './ButtonCollect'; export { default as PlayerBar } from './AudioPlayer/PlayerBar'; export { default as AudioPlayer } from './AudioPlayer/Player'; -// Song -export { default as SongCard } from './Song/SongCard'; -export { default as SongCardList } from './Song/SongCardList'; +// SongCard +export { default as SongCard } from './SongCard/SongCard'; +export { default as SongCardList } from './SongCard/SongCardList'; // Comment export { default as Comment } from './Comment/Comment'; @@ -39,4 +42,4 @@ export { default as CommentForm } from './Comment/CommentForm'; export { default as CommentItem } from './Comment/CommentItem'; export { default as CommentList } from './Comment/CommentList'; export { default as PlayerButton } from './AudioPlayer/PlayerButton'; -export { default as Pagination } from './Pagination/index'; +export { default as Pagination } from './Pagination'; diff --git a/src/store/audio.ts b/src/store/audio.ts index 35796cd..b51e9d1 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -4,15 +4,13 @@ import { create } from 'zustand'; import { devtools, persist, createJSONStorage } from 'zustand/middleware'; interface AuioState { - /** 播放状态 */ - playStatus: boolean; - /** 播放列表id */ - playListId: string; - /** 播放顺序 */ + /** 播放状态 true: 播放 false: 暂停 */ + playState: boolean; + /** 播放顺序 list_loop: 列表循环 random: 随机 single: 单曲 */ order: PlayOrder; - /** 播放器显示状态 */ + /** 播放器显示状态 true: 显示 false: 隐藏 */ show: boolean; - /** 单曲卡牌展示 */ + /** 单曲卡牌展示 true: 显示 false: 隐藏 */ showCard: boolean; /** 当前音频id */ audioId: string; @@ -20,6 +18,7 @@ interface AuioState { playList: SongInfo[]; /** 播放队列 */ playQueue: SongInfo[]; + setPlayState: (state: boolean) => void; setOrder: (order: PlayOrder) => void; setAudioId: (id: string) => void; // 显示/隐藏播放器 @@ -27,7 +26,7 @@ interface AuioState { // 显示/隐藏单曲卡片 setShowCard: (value: boolean) => void; // 设置播放列表 - setPlayList: (params: { id: string; list: SongInfo[] }) => void; + setPlayList: (list: SongInfo[]) => void; // 切换歌曲 -1: 上一首 1: 下一首 switchSongByDiff: (diff: number) => void; } @@ -37,8 +36,20 @@ const useAuioState = create()( persist( (set, get) => { const setAudioId = (id: string) => { - if (id === get().audioId) return; // 当前歌曲 - if (get().playQueue.findIndex((item) => item.id === id) < 0) return; // 不在歌单内 + if (id === get().audioId) { + // 传入当前歌曲id 切换播放/暂停状态 + // set( + // produce((state) => { + // state.playState = !get().playState; + // }), + // ); + return; + } + + // 不在歌单内 + if (get().playQueue.findIndex((item) => item.id === id) < 0) { + return; + } set( produce((state) => { @@ -97,14 +108,19 @@ const useAuioState = create()( return { audioId: '', order: 'list_loop', - playStatus: false, + playState: false, show: false, showCard: false, - playListId: '', playList: [], playQueue: [], setAudioId, setOrder, + setPlayState: (value) => + set( + produce((state) => { + state.playState = value; + }), + ), setShow: (value) => set( produce((state) => { @@ -117,12 +133,12 @@ const useAuioState = create()( state.showCard = value; }), ), - setPlayList: (params) => { + setPlayList: (list) => { set( produce((state) => { - state.playListId = params.id; - state.playList = params.list; - state.playQueue = params.list; + state.playList = list; + state.order = 'list_loop'; + state.playQueue = list; }), ); },