feat: 动画调整
This commit is contained in:
@@ -54,6 +54,7 @@ let dynamicNewsCardRenderCount = 0;
|
|||||||
* @param {Function} onSearchFocus - 搜索框获得焦点回调
|
* @param {Function} onSearchFocus - 搜索框获得焦点回调
|
||||||
* @param {Function} onEventClick - 事件点击回调
|
* @param {Function} onEventClick - 事件点击回调
|
||||||
* @param {Function} onViewDetail - 查看详情回调
|
* @param {Function} onViewDetail - 查看详情回调
|
||||||
|
* @param {Object} trackingFunctions - PostHog 追踪函数集合
|
||||||
* @param {Object} ref - 用于滚动的ref
|
* @param {Object} ref - 用于滚动的ref
|
||||||
*/
|
*/
|
||||||
const DynamicNewsCard = forwardRef(({
|
const DynamicNewsCard = forwardRef(({
|
||||||
@@ -64,6 +65,7 @@ const DynamicNewsCard = forwardRef(({
|
|||||||
onSearchFocus,
|
onSearchFocus,
|
||||||
onEventClick,
|
onEventClick,
|
||||||
onViewDetail,
|
onViewDetail,
|
||||||
|
trackingFunctions = {},
|
||||||
...rest
|
...rest
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -205,9 +207,22 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
// 四排模式的事件点击处理(打开弹窗)
|
// 四排模式的事件点击处理(打开弹窗)
|
||||||
const handleFourRowEventClick = useCallback((event) => {
|
const handleFourRowEventClick = useCallback((event) => {
|
||||||
console.log('%c🔲 [四排模式] 点击事件,打开详情弹窗', 'color: #8B5CF6; font-weight: bold;', { eventId: event.id, title: event.title });
|
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);
|
setModalEvent(event);
|
||||||
onModalOpen();
|
onModalOpen();
|
||||||
}, [onModalOpen]);
|
}, [onModalOpen, trackingFunctions]);
|
||||||
|
|
||||||
// 初始加载 - 只在组件首次挂载且对应模式数据为空时执行
|
// 初始加载 - 只在组件首次挂载且对应模式数据为空时执行
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -302,6 +317,18 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
console.log('%c🎯 [首次加载] 自动选中第一个事件', 'color: #10B981; font-weight: bold;');
|
console.log('%c🎯 [首次加载] 自动选中第一个事件', 'color: #10B981; font-weight: bold;');
|
||||||
hasAutoSelectedFirstEvent.current = true;
|
hasAutoSelectedFirstEvent.current = true;
|
||||||
setSelectedEvent(currentPageEvents[0]);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +337,7 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
e => e.id === selectedEvent?.id
|
e => e.id === selectedEvent?.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [currentPageEvents, selectedEvent?.id, mode]);
|
}, [currentPageEvents, selectedEvent?.id, mode, trackingFunctions]);
|
||||||
|
|
||||||
// 组件卸载时清理选中状态
|
// 组件卸载时清理选中状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -364,7 +391,9 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
if (!cardHeaderElement || !cardBodyElement) return;
|
if (!cardHeaderElement || !cardBodyElement) return;
|
||||||
|
|
||||||
let ticking = false;
|
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 = () => {
|
const handleExternalScroll = () => {
|
||||||
@@ -375,7 +404,7 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
const rect = cardHeaderElement.getBoundingClientRect();
|
const rect = cardHeaderElement.getBoundingClientRect();
|
||||||
const elementTop = rect.top;
|
const elementTop = rect.top;
|
||||||
|
|
||||||
// 计算触发点:总导航高度 + 100px 偏移量
|
// 计算触发点:总导航高度 + 150px 偏移量
|
||||||
const triggerPoint = TOTAL_NAV_HEIGHT + TRIGGER_OFFSET;
|
const triggerPoint = TOTAL_NAV_HEIGHT + TRIGGER_OFFSET;
|
||||||
|
|
||||||
// 向上滑动:元素顶部到达触发点 → 激活固定模式
|
// 向上滑动:元素顶部到达触发点 → 激活固定模式
|
||||||
@@ -402,25 +431,31 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
|
|
||||||
// 检测向上滚动(deltaY < 0)
|
// 检测向上滚动(deltaY < 0)
|
||||||
if (e.deltaY < 0) {
|
if (e.deltaY < 0) {
|
||||||
// 查找所有滚动容器
|
window.requestAnimationFrame(() => {
|
||||||
const scrollContainers = cardBodyElement.querySelectorAll('[data-scroll-container]');
|
// 🎯 检查 1:CardHeader 位置(主要条件)
|
||||||
|
const rect = cardHeaderElement.getBoundingClientRect();
|
||||||
|
const elementTop = rect.top;
|
||||||
|
const exitPoint = TOTAL_NAV_HEIGHT + EXIT_OFFSET;
|
||||||
|
|
||||||
if (scrollContainers.length === 0) {
|
// 🎯 检查 2:左侧事件列表滚动位置(辅助条件)
|
||||||
// 如果没有找到标记的容器,查找所有可滚动元素
|
const eventListContainers = cardBodyElement.querySelectorAll('[data-event-list-container]');
|
||||||
const allScrollable = cardBodyElement.querySelectorAll('[style*="overflow"]');
|
const allNearTop = eventListContainers.length === 0 ||
|
||||||
scrollContainers = allScrollable;
|
Array.from(eventListContainers).every(
|
||||||
}
|
container => container.scrollTop <= EXIT_THRESHOLD
|
||||||
|
);
|
||||||
|
|
||||||
// 检查是否所有滚动容器都在顶部
|
// 🎯 退出条件:CardHeader 超过退出点 OR 左侧列表接近顶部
|
||||||
const allAtTop = scrollContainers.length === 0 ||
|
if (elementTop > exitPoint || allNearTop) {
|
||||||
Array.from(scrollContainers).every(
|
setIsFixedMode(false);
|
||||||
container => container.scrollTop === 0
|
console.log('🔓 恢复正常文档流模式', {
|
||||||
);
|
elementTop,
|
||||||
|
exitPoint,
|
||||||
if (allAtTop) {
|
listNearTop: allNearTop,
|
||||||
setIsFixedMode(false);
|
exitThreshold: EXIT_THRESHOLD,
|
||||||
console.log('🔓 恢复正常文档流模式(内部滚动到顶部)');
|
reason: elementTop > exitPoint ? 'CardHeader位置' : '左侧列表滚动'
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -490,6 +525,7 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
filters={filters}
|
filters={filters}
|
||||||
mode={mode}
|
mode={mode}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
|
trackingFunctions={trackingFunctions}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
Reference in New Issue
Block a user