fix(AudioPlayer):

1. Fix next handle when last song;
2. Close ssr;
mack-mac
mackt 7 months ago
parent e452b61bd7
commit 40fffcda82

@ -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<number>(0); // 音频进度
const isReady = useRef<boolean>(false); // 是否完成加载
const { duration } = audioRef.current; // 音频总时长;
const { playStatus, setPlayStatus, audio, switchSongByDiff } = useAudioStore(
useShallow((state) => ({
playStatus: state.playStatus,
setPlayStatus: state.setPlayStatus,
const { audio, switchSongByDiff } = useAudioStore(
useShallow((state) => {
return {
audio: state.audio,
playList: state.playList,
switchSongByDiff: state.switchSongByDiff,
})),
};
}),
);
// const musicPlayers = useRef<HTMLAudioElement | undefined>(typeof Audio !== 'undefined' ? new Audio('') : undefined);
const audioRef = useRef(new Audio(''));
const [isPlaying, setIsPlaying] = useState(false); // 播放状态
const [trackProgress, setTrackProgress] = useState<number>(0); // 音频进度(s)
const isFirst = useRef<boolean>(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 (
<div>
<PlayerControl
playStatus={playStatus}
playStatus={isPlaying}
audio={audio}
duration={duration}
onPlay={handlePlay}

@ -1,11 +1,13 @@
'use client';
import { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import Player from './Player';
import { debounce } from 'lodash';
// import { debounce } from 'lodash';
export default function PlayerBar({ className }: { className?: string }) {
const PlayerBar = ({ className }: { className?: string }) => {
let oldScrollY: number = 0;
function handleScroll() {
if (window.scrollY > oldScrollY) {
@ -40,4 +42,6 @@ export default function PlayerBar({ className }: { className?: string }) {
</div>
</div>
);
}
};
export default dynamic(() => Promise.resolve(PlayerBar), { ssr: false });

@ -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,

@ -9,29 +9,29 @@ interface AuioState {
playStatus: boolean;
/** 播放列表id */
playListId: string;
/** 修改播放列表id */
setPlayListId: (id: string) => void;
/** 播放器显示状态 */
show: boolean;
/** 正在播放的音频信息 */
audio: SongInfo | null;
/**
/** 播放列表 */
playList: Array<SongInfo>;
/**
* @description
* @param id id playList
*/
setAudio: (id: string | null) => void;
/** 播放列表 */
playList: Array<SongInfo>;
/** 播放/暂停 */
setPlayStatus: (value: boolean) => void;
/** 显示/隐藏播放器 */
/** @description 显示/隐藏播放器 */
setShow: (value: boolean) => void;
/** 设置播放列表 */
/** @description 设置播放列表 */
setPlayList: (params: { id: string; list: SongInfo[] }) => void;
/** 获取歌曲信息 */
/** @description 获取歌曲信息 */
getSongInfoById: (id: string) => Promise<boolean>;
/** 根据id切换歌曲 */
switchSongById: (id: string) => Promise<boolean>;
/** 切换歌曲 */
/**
* @description
* @diff -1: 1:
*/
switchSongByDiff: (diff: number) => void;
}
@ -39,55 +39,71 @@ const useAuioState = create<AuioState>()(
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,

@ -53,7 +53,7 @@ const useUserStore = create<UserState>()(
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<UserState>()(
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);

Loading…
Cancel
Save