From 4a266aaeefe2957811b97751e38c526b0310a4ac Mon Sep 17 00:00:00 2001 From: Mahiru Date: Sat, 15 Feb 2025 20:39:09 +0800 Subject: [PATCH] feat: implement infinite scrolling for backlog items --- packages/webgal/src/UI/Backlog/Backlog.tsx | 53 +++++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/packages/webgal/src/UI/Backlog/Backlog.tsx b/packages/webgal/src/UI/Backlog/Backlog.tsx index 86d00e657..57c56bf79 100644 --- a/packages/webgal/src/UI/Backlog/Backlog.tsx +++ b/packages/webgal/src/UI/Backlog/Backlog.tsx @@ -16,17 +16,52 @@ export const Backlog = () => { // logger.info('Backlog render'); const { playSeEnter, playSeClick } = useSoundEffect(); const GUIStore = useSelector((state: RootState) => state.GUI); + const isBacklogOpen = GUIStore.showBacklog; const dispatch = useDispatch(); const iconSize = '0.8em'; const [indexHide, setIndexHide] = useState(false); const [isDisableScroll, setIsDisableScroll] = useState(false); + const [limit, setLimit] = useState(20); + useEffect(() => { + if (!isBacklogOpen) { + return; + } + let options = { + root: null, + rootMargin: '0px', + threshold: [1.0], + }; + + let observer = new IntersectionObserver((entries) => { + if ((entries?.[0]?.intersectionRatio ?? 0) <= 0) return; + setLimit(limit + 20); + }, options); + + const observeTarget = document.querySelector(`#backlog_item_${limit - 5}`); + if (observeTarget) { + observer.observe(observeTarget); + } + + return () => { + observer.disconnect(); + }; + }, [limit, isBacklogOpen]); + + useEffect(() => { + if (!isBacklogOpen) { + setLimit(20); + } + }, [isBacklogOpen]); + let timeRef = useRef>(); // 缓存一下vdom const backlogList = useMemo(() => { let backlogs = []; + const current_backlog_len = WebGAL.backlogManager.getBacklog().length; // logger.info('backlogList render'); - for (let i = 0; i < WebGAL.backlogManager.getBacklog().length; i++) { - const backlogItem = WebGAL.backlogManager.getBacklog()[i]; + for (let i = 0; i < Math.min(current_backlog_len, limit); i++) { + const indexOfBacklog = current_backlog_len - i - 1; + const backlogItem = WebGAL.backlogManager.getBacklog()[indexOfBacklog]; const showTextArray = compileSentence(backlogItem.currentStageState.showText, 3, true, false); const showTextArray2 = showTextArray.map((line) => { return line.map((c) => { @@ -70,7 +105,8 @@ export const Backlog = () => { const singleBacklogView = (
@@ -78,7 +114,7 @@ export const Backlog = () => {
{ playSeClick(); - jumpFromBacklog(i); + jumpFromBacklog(indexOfBacklog); e.preventDefault(); e.stopPropagation(); }} @@ -92,7 +128,9 @@ export const Backlog = () => { onClick={() => { playSeClick(); // 获取到播放 backlog 语音的元素 - const backlog_audio_element: any = document.getElementById('backlog_audio_play_element_' + i); + const backlog_audio_element: any = document.getElementById( + 'backlog_audio_play_element_' + indexOfBacklog, + ); if (backlog_audio_element) { backlog_audio_element.currentTime = 0; const userDataStore = webgalStore.getState().userData; @@ -113,15 +151,16 @@ export const Backlog = () => {
{showTextElementList}
-
); - backlogs.unshift(singleBacklogView); + backlogs.push(singleBacklogView); } return backlogs; }, [ WebGAL.backlogManager.getBacklog()[WebGAL.backlogManager.getBacklog().length - 1]?.saveScene?.currentSentenceId ?? 0, + limit, ]); useEffect(() => { /* 切换为展示历史记录时触发 */