diff --git a/public/img/audio-player/CD.png b/public/img/audio-player/CD.png new file mode 100644 index 0000000..ae790dd Binary files /dev/null and b/public/img/audio-player/CD.png differ diff --git a/src/components/AudioPlayer/Player.tsx b/src/components/AudioPlayer/Player.tsx index f17a820..87237e4 100644 --- a/src/components/AudioPlayer/Player.tsx +++ b/src/components/AudioPlayer/Player.tsx @@ -11,15 +11,23 @@ import PlayerControl from './PlayerControl'; import useAudioStore from '@/store/audio'; -export default function AudioPlayer({ className }: { className?: string }) { - const { audioId, order, playQueue, switchSongByDiff, setOrder } = useAudioStore( +export default function AudioPlayer({ + className, + onSwitchShowCard, +}: { + className?: string; + onSwitchShowCard: () => void; +}) { + const { audioId, order, playQueue, showCard, switchSongByDiff, setOrder, setShowCard } = useAudioStore( useShallow((state) => { return { audioId: state.audioId, order: state.order, playQueue: state.playQueue, + showCard: state.showCard, setOrder: state.setOrder, switchSongByDiff: state.switchSongByDiff, + setShowCard: state.setShowCard, }; }), ); @@ -127,6 +135,7 @@ export default function AudioPlayer({ className }: { className?: string }) { order={order} audio={audio} duration={duration} + showCard={showCard} onPlay={handlePlay} onPrev={() => handleSwitchAudio(-1)} onNext={() => handleSwitchAudio(1)} @@ -134,6 +143,7 @@ export default function AudioPlayer({ className }: { className?: string }) { className={className} trackProgress={trackProgress} onChangeProgress={handleChangeProgress} + onSwitchShowCard={onSwitchShowCard} /> ); } diff --git a/src/components/AudioPlayer/PlayerBar.tsx b/src/components/AudioPlayer/PlayerBar.tsx index b267478..21a99f5 100644 --- a/src/components/AudioPlayer/PlayerBar.tsx +++ b/src/components/AudioPlayer/PlayerBar.tsx @@ -3,12 +3,32 @@ import { useEffect } from 'react'; import dynamic from 'next/dynamic'; +import { useShallow } from 'zustand/react/shallow'; import Player from './Player'; +import PlayerCard from './PlayerCard'; -// import { debounce } from 'lodash'; +import useAudioStore from '@/store/audio'; const PlayerBar = ({ className }: { className?: string }) => { + const { audioId, order, playQueue, showCard, switchSongByDiff, setOrder, setShowCard } = useAudioStore( + useShallow((state) => { + return { + audioId: state.audioId, + order: state.order, + playQueue: state.playQueue, + showCard: state.showCard, + setOrder: state.setOrder, + switchSongByDiff: state.switchSongByDiff, + setShowCard: state.setShowCard, + }; + }), + ); + + const handleSwitchShowCard = () => { + setShowCard(!showCard); + }; + // let oldScrollY: number = 0; // function handleScroll() { // if (window.scrollY > oldScrollY) { @@ -23,6 +43,13 @@ const PlayerBar = ({ className }: { className?: string }) => { // oldScrollY = window.scrollY; // } + useEffect(() => { + // window.addEventListener('scroll', handleScroll); + // return () => { + // window.removeEventListener('scroll', handleScroll); + // }; + }, []); + useEffect(() => { // window.addEventListener('scroll', handleScroll); // return () => { @@ -42,9 +69,12 @@ const PlayerBar = ({ className }: { className?: string }) => { className={`fixed w-[100vw] h-[130px] bg-[#fff] shadow-lg shadow-black-[0_0_10px] z-10 ${className}`} style={{ bottom: 0 }} > -
- + {/* 播放器 */} +
+
+ {/* 单曲卡片 */} +
); }; diff --git a/src/components/AudioPlayer/PlayerCard.tsx b/src/components/AudioPlayer/PlayerCard.tsx new file mode 100644 index 0000000..cecfcb8 --- /dev/null +++ b/src/components/AudioPlayer/PlayerCard.tsx @@ -0,0 +1,82 @@ +import Image from 'next/image'; +import { useShallow } from 'zustand/react/shallow'; + +import styles from './index.module.css'; + +import { SongCardList } from '@/components'; +import useAudioStore from '@/store/audio'; + +interface Prop { + // onClose: () => void; + show: boolean; + className?: string; +} + +export default function PlayerCard({ show, className }: Prop) { + const { audioId, playQueue } = useAudioStore( + useShallow((state) => { + return { + audioId: state.audioId, + playQueue: state.playQueue, + }; + }), + ); + + const miniClass = 'w-100vw translate-y-100vh'; // 缩小时的样式 + const largeClass = 'w-[100vw] translate-y-[-130px]'; // 放大后的样式 + + const audioInfo = playQueue.find((item) => item.id === audioId); + + console.log(audioInfo); + + return ( +
+
+ {/* 单曲信息 */} +
+ {/* 专辑封面 */} + {/* 阴影 */} +
+
+ {audioInfo?.pic && ( + pic + )} +
+
+ + {/* 歌曲名 */} +

{audioInfo?.title ?? ''}

+ {/* 歌手/专辑 */} + {audioInfo?.artist && audioInfo?.album && ( +

{`${audioInfo.artist}/${audioInfo.album}`}

+ )} + {/* 歌词 */} +
{audioInfo?.lrc ?
:
暂无歌词
}
+
+ + {/* 播放列表 */} +
+ + +
+
+
+ ); +} diff --git a/src/components/AudioPlayer/PlayerControl.tsx b/src/components/AudioPlayer/PlayerControl.tsx index 8efddae..ebfe27d 100644 --- a/src/components/AudioPlayer/PlayerControl.tsx +++ b/src/components/AudioPlayer/PlayerControl.tsx @@ -1,5 +1,7 @@ 'use client'; +// 样式层 + import Image from 'next/image'; import { secondToDate } from '@/utils/time'; @@ -12,6 +14,8 @@ interface Props { audio: SongInfo | null; order: PlayOrder; playStatus: boolean; + showCard: boolean; + onSwitchShowCard: () => void; onPlay: () => void; onOrder: () => void; onPrev: () => void; @@ -26,11 +30,13 @@ export default function AudioPlayer({ audio, order, playStatus, + showCard, onPlay, onOrder, onPrev, onNext, onChangeProgress, + onSwitchShowCard, trackProgress, duration, className, @@ -51,7 +57,8 @@ export default function AudioPlayer({
{/* 专辑封面 */}
{audio?.pic && ( music diff --git a/src/components/AudioPlayer/index.module.css b/src/components/AudioPlayer/index.module.css index 8bca1de..20cbc9e 100644 --- a/src/components/AudioPlayer/index.module.css +++ b/src/components/AudioPlayer/index.module.css @@ -24,6 +24,13 @@ background-size: 28px; } +/* 专辑封面 阴影 */ +.album_shoadow { + background: rgba(0, 0, 0, 0.08); + box-shadow: 27px 10px 30px -12px rgba(0, 0, 0, 0.25); + border-radius: 3px; +} + .range-input { -webkit-appearance: none; width: 100%; diff --git a/src/store/audio.ts b/src/store/audio.ts index b4c8f0e..94271b6 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -12,7 +12,11 @@ interface AuioState { order: PlayOrder; /** 播放器显示状态 */ show: boolean; + /** 单曲卡牌展示 */ + showCard: boolean; + /** 当前音频id */ audioId: string; + audioInfo: SongInfo | null; /** 歌单列表 */ playList: SongInfo[]; /** 播放队列 */ @@ -21,6 +25,8 @@ interface AuioState { setAudioId: (id: string) => void; // 显示/隐藏播放器 setShow: (value: boolean) => void; + // 显示/隐藏单曲卡片 + setShowCard: (value: boolean) => void; // 设置播放列表 setPlayList: (params: { id: string; list: SongInfo[] }) => void; // 切换歌曲 -1: 上一首 1: 下一首 @@ -94,9 +100,11 @@ const useAuioState = create()( order: 'list_loop', playStatus: false, show: false, + showCard: false, playListId: '', playList: [], playQueue: [], + audioInfo: get()?.playList.length ? get().playList.find((item) => item.id === get().audioId) : null, setAudioId, setOrder, setShow: (value) => @@ -105,6 +113,12 @@ const useAuioState = create()( state.show = value; }), ), + setShowCard: (value) => + set( + produce((state) => { + state.showCard = value; + }), + ), setPlayList: (params) => { set( produce((state) => {