From 3574f5391fbd93730557dada186b2eaef7bac7ef Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Fri, 7 Nov 2025 15:17:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8A=A8=E7=94=BB=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Community/components/DynamicNewsCard.js | 78 ++++++++++++++----- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/src/views/Community/components/DynamicNewsCard.js b/src/views/Community/components/DynamicNewsCard.js index e4ca1150..b355e42f 100644 --- a/src/views/Community/components/DynamicNewsCard.js +++ b/src/views/Community/components/DynamicNewsCard.js @@ -54,6 +54,7 @@ let dynamicNewsCardRenderCount = 0; * @param {Function} onSearchFocus - 搜索框获得焦点回调 * @param {Function} onEventClick - 事件点击回调 * @param {Function} onViewDetail - 查看详情回调 + * @param {Object} trackingFunctions - PostHog 追踪函数集合 * @param {Object} ref - 用于滚动的ref */ const DynamicNewsCard = forwardRef(({ @@ -64,6 +65,7 @@ const DynamicNewsCard = forwardRef(({ onSearchFocus, onEventClick, onViewDetail, + trackingFunctions = {}, ...rest }, ref) => { const dispatch = useDispatch(); @@ -205,9 +207,22 @@ const [currentMode, setCurrentMode] = useState('vertical'); // 四排模式的事件点击处理(打开弹窗) const handleFourRowEventClick = useCallback((event) => { console.log('%c🔲 [四排模式] 点击事件,打开详情弹窗', 'color: #8B5CF6; font-weight: bold;', { eventId: event.id, title: event.title }); + + // 🎯 追踪事件详情打开 + if (trackingFunctions.trackNewsDetailOpened) { + trackingFunctions.trackNewsDetailOpened({ + eventId: event.id, + eventTitle: event.title, + importance: event.importance, + source: 'four_row_mode', + displayMode: 'modal', + timestamp: new Date().toISOString(), + }); + } + setModalEvent(event); onModalOpen(); - }, [onModalOpen]); + }, [onModalOpen, trackingFunctions]); // 初始加载 - 只在组件首次挂载且对应模式数据为空时执行 useEffect(() => { @@ -302,6 +317,18 @@ const [currentMode, setCurrentMode] = useState('vertical'); console.log('%c🎯 [首次加载] 自动选中第一个事件', 'color: #10B981; font-weight: bold;'); hasAutoSelectedFirstEvent.current = true; setSelectedEvent(currentPageEvents[0]); + + // 🎯 追踪事件点击(首次自动选中) + if (trackingFunctions.trackNewsArticleClicked) { + trackingFunctions.trackNewsArticleClicked({ + eventId: currentPageEvents[0].id, + eventTitle: currentPageEvents[0].title, + importance: currentPageEvents[0].importance, + source: 'auto_select_first', + displayMode: mode, + timestamp: new Date().toISOString(), + }); + } return; } @@ -310,7 +337,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); e => e.id === selectedEvent?.id ); } - }, [currentPageEvents, selectedEvent?.id, mode]); + }, [currentPageEvents, selectedEvent?.id, mode, trackingFunctions]); // 组件卸载时清理选中状态 useEffect(() => { @@ -364,7 +391,9 @@ const [currentMode, setCurrentMode] = useState('vertical'); if (!cardHeaderElement || !cardBodyElement) return; let ticking = false; - const TRIGGER_OFFSET = 100; // 提前 100px 触发 + const TRIGGER_OFFSET = 150; // 提前 150px 触发(进入固定模式) + const EXIT_OFFSET = 200; // 提前 200px 退出(退出比进入更容易) + const EXIT_THRESHOLD = 30; // 接近顶部 30px 内即可退出 // 外部滚动监听:触发固定模式 const handleExternalScroll = () => { @@ -375,7 +404,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); const rect = cardHeaderElement.getBoundingClientRect(); const elementTop = rect.top; - // 计算触发点:总导航高度 + 100px 偏移量 + // 计算触发点:总导航高度 + 150px 偏移量 const triggerPoint = TOTAL_NAV_HEIGHT + TRIGGER_OFFSET; // 向上滑动:元素顶部到达触发点 → 激活固定模式 @@ -402,25 +431,31 @@ const [currentMode, setCurrentMode] = useState('vertical'); // 检测向上滚动(deltaY < 0) if (e.deltaY < 0) { - // 查找所有滚动容器 - const scrollContainers = cardBodyElement.querySelectorAll('[data-scroll-container]'); + window.requestAnimationFrame(() => { + // 🎯 检查 1:CardHeader 位置(主要条件) + const rect = cardHeaderElement.getBoundingClientRect(); + const elementTop = rect.top; + const exitPoint = TOTAL_NAV_HEIGHT + EXIT_OFFSET; - if (scrollContainers.length === 0) { - // 如果没有找到标记的容器,查找所有可滚动元素 - const allScrollable = cardBodyElement.querySelectorAll('[style*="overflow"]'); - scrollContainers = allScrollable; - } + // 🎯 检查 2:左侧事件列表滚动位置(辅助条件) + const eventListContainers = cardBodyElement.querySelectorAll('[data-event-list-container]'); + const allNearTop = eventListContainers.length === 0 || + Array.from(eventListContainers).every( + container => container.scrollTop <= EXIT_THRESHOLD + ); - // 检查是否所有滚动容器都在顶部 - const allAtTop = scrollContainers.length === 0 || - Array.from(scrollContainers).every( - container => container.scrollTop === 0 - ); - - if (allAtTop) { - setIsFixedMode(false); - console.log('🔓 恢复正常文档流模式(内部滚动到顶部)'); - } + // 🎯 退出条件:CardHeader 超过退出点 OR 左侧列表接近顶部 + if (elementTop > exitPoint || allNearTop) { + setIsFixedMode(false); + console.log('🔓 恢复正常文档流模式', { + elementTop, + exitPoint, + listNearTop: allNearTop, + exitThreshold: EXIT_THRESHOLD, + reason: elementTop > exitPoint ? 'CardHeader位置' : '左侧列表滚动' + }); + } + }); } }; @@ -490,6 +525,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); filters={filters} mode={mode} pageSize={pageSize} + trackingFunctions={trackingFunctions} />