You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在点击锚点(a标签)子元素时阻止路由跳转?(React/Next)

实现锚点子元素点击阻止跳转并禁用NProgress

需求说明

点击<a>标签的子元素(如示例中的“Add to favorites”容器)时,需要执行event.preventDefault()阻止默认路由跳转,且不启动NProgress;点击<a>标签本身则正常跳转并启动NProgress。

示例HTML结构:

<a href="/product/product-id">
I am a product
  <div>
    Add to favorites
   </div>
</a>

修改思路

在全局点击监听的handleClick函数中,先判断点击的目标元素是否就是<a>标签本身:

  • 如果点击的是子元素(target !== anchor),直接阻止默认行为并返回,不执行后续NProgress逻辑
  • 如果点击的是<a>标签本身,继续执行原有的路由判断和NProgress控制逻辑

修改后的完整代码

'use client';

export default function NextNProgress() {
    useEffect(() => {
        NProgress.configure();

        function isAnchorOfCurrentUrl(currentUrl: string, newUrl: string) {
            const currentUrlObj = new URL(currentUrl);
            const newUrlObj = new URL(newUrl);
            if (
                currentUrlObj.hostname === newUrlObj.hostname &&
                currentUrlObj.pathname === newUrlObj.pathname &&
                currentUrlObj.search === newUrlObj.search
            ) {
                const currentHash = currentUrlObj.hash;
                const newHash = newUrlObj.hash;
                return (
                    currentHash !== newHash &&
                    currentUrlObj.href.replace(currentHash, '') === newUrlObj.href.replace(newHash, '')
                );
            }
            return false;
        }

        const htmlElements = document.querySelectorAll('html');

        function findClosestAnchor(element: HTMLElement | null): HTMLAnchorElement | null {
            while (element && element.tagName.toLowerCase() !== 'a') {
                element = element.parentElement;
            }
            return element as HTMLAnchorElement;
        }

        function handleClick(event: MouseEvent) {
            try {
                const target = event.target as HTMLElement;
                const anchor = findClosestAnchor(target);
                const newUrl = anchor?.href;
                
                // 核心判断:点击锚点子元素时阻止跳转并返回
                if (anchor && target !== anchor) {
                    event.preventDefault();
                    return;
                }

                if (newUrl) {
                    const currentUrl = window.location.href;
                    const isExternalLink = anchor.target === '_blank';
                    const isBlob = newUrl.startsWith('blob:');
                    const isAnchor = isAnchorOfCurrentUrl(currentUrl, newUrl);
                    if (newUrl === currentUrl || isAnchor || isExternalLink || isBlob || event.ctrlKey) {
                        NProgress.start();
                        NProgress.done();
                        [].forEach.call(htmlElements, function (el: Element) {
                            el.classList.remove('nprogress-busy');
                        });
                    } else {
                        NProgress.start();
                        (function (history) {
                            const pushState = history.pushState;
                            history.pushState = function () {
                                NProgress.done();
                                [].forEach.call(htmlElements, function (el: Element) {
                                    el.classList.remove('nprogress-busy');
                                });
                             
                                return pushState.apply(history, arguments as any);
                            };
                        })(window.history);
                    }
                }
            } catch (err) {
                NProgress.start();
                NProgress.done();
            }
        }

        document.addEventListener('click', handleClick);

        return () => {
            document.removeEventListener('click', handleClick);
        };
    }, []);

    return null; // 无UI组件返回null,若原有styles为自定义样式可替换回return styles
}

代码说明

  • 新增的if (anchor && target !== anchor)逻辑:当找到最近的<a>标签,且点击目标不是标签本身时,直接拦截默认跳转行为,跳过后续NProgress启动流程
  • 原有的路由判断、NProgress配置逻辑完全保留,仅在最前端加入子元素点击的拦截处理

内容的提问来源于stack exchange,提问作者user20670800

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:48:22