如何在点击锚点(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
相关产品推荐
相关产品推荐

