近期有个需求是在H5页面实现:
1、点击Tab标签定位至对应模块
2、页面滚动至某一模块时,展示对应锚点
3、Tab标签滚动吸顶
注意:页面滚动至某一模块时,展示对应锚点。可以从下往上计算 各个模块与页面顶部的距离和Tab标签的高度来判读哪个模块当前在可视区,从而选中对应的Tab标签。代码如下:
const [activeTab, setActiveTab] = useState('abstract');
const module1Ref = useRef<any>(null);
const module2Ref = useRef<any>(null);
const module3Ref = useRef<any>(null);
const [shouldScrollEvent, setShouldScrollEvent] = useState(true);
const onActiveTabChange = (newTab: string) => {
setShouldScrollEvent(false);
setActiveTab(newTab);
const paperDetailBox = document.getElementById('paperDetailBox');
switch (newTab) {
case 'tab1':
paperDetailBox?.scrollTo(0,module1.current?.offsetTop - 99);
break;
case 'tab2':
paperDetailBox?.scrollTo(0, module2Ref.current?.offsetTop - 99);
break;
case 'tab3':
paperDetailBox?.scrollTo(0, module3Ref.current?.offsetTop - 99);
break;
default:
break;
}
};
useEffect(() => {
const paperDetailBox = document.getElementById('paperDetailBox');
const handleScroll = () => {
if (!shouldScrollEvent) {
return;
}
const focusedElement = document.querySelector('.ant-tabs-tab-btn:focus');
if (focusedElement) {
(focusedElement as HTMLElement).blur();
}
const tabHeight = document.querySelector('#tabs')?.clientHeight || 0;
const cont3Rect = tab3Ref.current?.getBoundingClientRect();
const cont2Rect = tab2Ref.current?.getBoundingClientRect();
if (cont3Rect && cont3Rect.top - 49 <= tabHeight) {
setActiveTab('tab3');
} else if (cont2Rect && cont2Rect.top - 49 <= tabHeight) {
setActiveTab('tab2');
} else {
setActiveTab('tab1');
}
};
if (paperDetailBox) {
setShouldScrollEvent(true);
paperDetailBox.addEventListener('scroll', handleScroll);
}
return () => {
paperDetailBox?.removeEventListener('scroll', handleScroll);
};
}, [detail, shouldScrollEvent]);
坑1: 代码里加了一个shouldScrollEvent事件是因为,点击tab标签时也会触发
在这个示例中,我添加了一个新的状态变量 shouldScrollEvent来判断当页面滚动时是否要执行默认选中效果,因为tab切换时,页面会滚动到对应的模块,会间接执行页面滚动的监听事件,所以当用户点击tab切换时要阻止滚动监听
。当你开始滚动页面时,滚动事件处理器会将 shouldScrollEvent
设置回 true
,将继续监听滚动事件。
坑2: 通过页面滚动使antd的tab标签聚焦,之前点击选中而聚焦的元素 color并失去焦点
解决办法:通过监听页面滚动事件,然后在滚动时移除之前聚焦元素的焦点状态来实现这个需求
useEffect(() => {
const handleScroll = () => {
const focusedElement = document.querySelector('.ant-tabs-tab-btn:focus');
if (focusedElement) {
(focusedElement as HTMLElement).blur();
}
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);