H5端 Tab标签滚动时吸顶&滚动至对应模块选中对应tab&开发中遇到的坑

近期有个需求是在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);
        };
    }, []);
  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值