From 40fffcda823d9afb48c208bf62a6e599b0e65e5b Mon Sep 17 00:00:00 2001 From: mackt <1033530438@qq.com> Date: Mon, 8 Apr 2024 13:06:15 +0800 Subject: [PATCH] fix(AudioPlayer): 1. Fix next handle when last song; 2. Close ssr; --- src/components/AudioPlayer/Player.tsx | 69 ++++++++++---------- src/components/AudioPlayer/PlayerBar.tsx | 10 ++- src/components/Song/SongCardList.tsx | 4 +- src/store/audio.ts | 82 ++++++++++++++---------- src/store/user.ts | 4 +- 5 files changed, 94 insertions(+), 75 deletions(-) diff --git a/src/components/AudioPlayer/Player.tsx b/src/components/AudioPlayer/Player.tsx index 5d884ca..c85aefc 100644 --- a/src/components/AudioPlayer/Player.tsx +++ b/src/components/AudioPlayer/Player.tsx @@ -14,25 +14,26 @@ import PlayerControl from './PlayerControl'; import useAudioStore from '@/store/audio'; export default function AudioPlayer({ className }: { className?: string }) { - const audioRef = useRef(new Audio()); - const [trackProgress, setTrackProgress] = useState(0); // 音频进度 - const isReady = useRef(false); // 是否完成加载 - - const { duration } = audioRef.current; // 音频总时长; - - const { playStatus, setPlayStatus, audio, switchSongByDiff } = useAudioStore( - useShallow((state) => ({ - playStatus: state.playStatus, - setPlayStatus: state.setPlayStatus, - audio: state.audio, - playList: state.playList, - switchSongByDiff: state.switchSongByDiff, - })), + const { audio, switchSongByDiff } = useAudioStore( + useShallow((state) => { + return { + audio: state.audio, + playList: state.playList, + switchSongByDiff: state.switchSongByDiff, + }; + }), ); + // const musicPlayers = useRef(typeof Audio !== 'undefined' ? new Audio('') : undefined); + const audioRef = useRef(new Audio('')); + const [isPlaying, setIsPlaying] = useState(false); // 播放状态 + const [trackProgress, setTrackProgress] = useState(0); // 音频进度(s) + const isFirst = useRef(false); // 第一次进入 + const { duration } = audioRef.current; // 音频总时长(s) + // 播放/暂停 const handlePlay = () => { - setPlayStatus(!playStatus); + setIsPlaying(!isPlaying); }; // 上一首 @@ -45,47 +46,47 @@ export default function AudioPlayer({ className }: { className?: string }) { switchSongByDiff(1); }; - // 调整进度 + // 调整播放进度 const handleChangeProgress = (value: string) => { audioRef.current.currentTime = Number(value); setTrackProgress(audioRef.current.currentTime); }; - // 给 audio 绑定监听 + // 监听音频进度 + const onTimeUpdate = () => { + if (audioRef.current.ended) handlePlayNext(); + setTrackProgress(audioRef.current.currentTime); + }; + + // 给 audio 绑定 timeupdate 监听 const handleTimeUpdate = (status: boolean) => { status ? audioRef.current.addEventListener('timeupdate', onTimeUpdate) : audioRef.current.removeEventListener('timeupdate', onTimeUpdate); }; - // 监听进度 - const onTimeUpdate = () => { - if (audioRef.current.ended) handlePlayNext(); - setTrackProgress(audioRef.current.currentTime); - }; - - // 监听播放/暂停 + // 播放/暂停 useEffect(() => { - playStatus ? audioRef.current.play() : audioRef.current.pause(); - }, [playStatus]); + isPlaying ? audioRef.current.play() : audioRef.current.pause(); + }, [isPlaying]); - // 监听切换歌曲 + // 切换歌曲 useEffect(() => { - console.log('触发'); - handleTimeUpdate(false); audioRef.current.pause(); if (!audio) return; audioRef.current = new Audio(audio.src); - - if (isReady.current) { + setTrackProgress(audioRef.current.currentTime); + console.log('id变化', { audio, isFirst: isFirst.current }); + if (isFirst.current) { audioRef.current.play(); - setPlayStatus(true); + setIsPlaying(true); handleTimeUpdate(true); } else { - isReady.current = true; + isFirst.current = true; } }, [audio]); + // 卸载时的处理 useEffect(() => { return () => { audioRef.current.pause(); @@ -96,7 +97,7 @@ export default function AudioPlayer({ className }: { className?: string }) { return (
{ let oldScrollY: number = 0; function handleScroll() { if (window.scrollY > oldScrollY) { @@ -40,4 +42,6 @@ export default function PlayerBar({ className }: { className?: string }) {
); -} +}; + +export default dynamic(() => Promise.resolve(PlayerBar), { ssr: false }); diff --git a/src/components/Song/SongCardList.tsx b/src/components/Song/SongCardList.tsx index 9624dcd..45c219f 100644 --- a/src/components/Song/SongCardList.tsx +++ b/src/components/Song/SongCardList.tsx @@ -15,10 +15,8 @@ interface Props { } export default function JournalItem({ listId, songList, className }: Props) { - const { playStatus, setPlayStatus, setPlayList, audio, playList, playListId, setAudio } = useAudioStore( + const { setPlayList, audio, playList, playListId, setAudio } = useAudioStore( useShallow((state) => ({ - playStatus: state.playStatus, - setPlayStatus: state.setPlayStatus, setplayList: state.setPlayList, audio: state.audio, setAudio: state.setAudio, diff --git a/src/store/audio.ts b/src/store/audio.ts index 38952fd..3e33968 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -9,29 +9,29 @@ interface AuioState { playStatus: boolean; /** 播放列表id */ playListId: string; - /** 修改播放列表id */ - setPlayListId: (id: string) => void; /** 播放器显示状态 */ show: boolean; /** 正在播放的音频信息 */ audio: SongInfo | null; - /** 设置正在播放的音频 + /** 播放列表 */ + playList: Array; + /** + * @description 设置正在播放的音频 * @param id 音频 id,必须在 playList 内 */ setAudio: (id: string | null) => void; - /** 播放列表 */ - playList: Array; - /** 播放/暂停 */ - setPlayStatus: (value: boolean) => void; - /** 显示/隐藏播放器 */ + /** @description 显示/隐藏播放器 */ setShow: (value: boolean) => void; - /** 设置播放列表 */ + /** @description 设置播放列表 */ setPlayList: (params: { id: string; list: SongInfo[] }) => void; - /** 获取歌曲信息 */ + /** @description 获取歌曲信息 */ getSongInfoById: (id: string) => Promise; /** 根据id切换歌曲 */ switchSongById: (id: string) => Promise; - /** 切换歌曲 */ + /** + * @description 切换歌曲 + * @diff 切歌距离 -1: 上一首 1: 下一首 + */ switchSongByDiff: (diff: number) => void; } @@ -39,55 +39,71 @@ const useAuioState = create()( devtools( persist( (set, get) => { - // 设置当前播放的音频 const setAudio = (id: string | null) => { + console.log('触发setAudio'); const audio = get().playList.find((item) => item?.id === id) || null; - set({ audio }); - set({ playStatus: true }); + set( + produce((state) => { + state.audio = audio; + }), + ); }; - // 根据 id 获取歌曲信息 + /** + * @description 根据 id 获取歌曲信息 + * @mark 暂时未使用,启用时需要修改逻辑,`set({ audio: res.data });`会导致歌曲自动播放 + */ const getSongInfoById = async (id: string) => { const res = await apiGetSongInfo(id); if (res.code === 200) set({ audio: res.data }); return res.code === 200; }; - // 设置播放列表 - const setPlayListId = (id: string) => { - set({ playListId: id }); - }; - - // 切歌 const switchSongByDiff = (diff: number) => { + if (diff === 0) return; const playList = get().playList; if (!playList) return; + const index = playList.findIndex((item) => item.id === get().audio?.id); - const nextIndex = index + diff; - if (nextIndex < 0) setAudio(playList[playList.length - 1].id); - if (nextIndex >= playList.length) setAudio(playList[0].id); - set({ audio: playList[nextIndex] }); - setAudio(playList[nextIndex].id); - return; + const nextIndex = index + diff; // 计算后的 index + + // 判断 index 是否越界,计算音频 id + let audioId = ''; + if (nextIndex < 0) { + audioId = playList[playList.length - 1].id; + } else if (nextIndex >= playList.length) { + audioId = playList[0].id; + } else { + audioId = playList[nextIndex].id; + } + + setAudio(audioId); }; return { playStatus: false, show: false, audio: null, - setAudio, playList: [], + setAudio, + setShow: (value) => + set( + produce((state) => { + state.show = value; + }), + ), switchSongById: async (id: string) => { const res = await getSongInfoById(id); return res; }, playListId: '', - setPlayListId, - setPlayStatus: (value) => set({ playStatus: value }), - setShow: (value) => set({ show: value }), setPlayList: (params) => { - set({ playListId: params.id }); - set({ playList: params.list }); + set( + produce((state) => { + state.playListId = params.id; + state.playList = params.list; + }), + ); }, getSongInfoById, switchSongByDiff, diff --git a/src/store/user.ts b/src/store/user.ts index 2659c9f..f892db1 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -53,7 +53,7 @@ const useUserStore = create()( thumbUpCount: 0, }; - const setUserInfo = (value: UserInfo) => set(produce((state) => void (state.userInfo = value))); + const setUserInfo = (value: UserInfo) => set(produce((state) => (state.userInfo = value))); const getUserInfo = async () => { const result = await apiGetMyUserInfo(); @@ -64,7 +64,7 @@ const useUserStore = create()( return { userInfo: initialUserInfo, showLogin: false, - setShowLogin: (value) => set({ showLogin: value }), + setShowLogin: (value) => set(produce((state) => (state.showLogin = value))), setUserInfo, userLogin: async (params) => { const result = await apiUserLogin(params);