Next.js <Link>导航后脚本不重新执行的解决方案求助
Next.js 单页导航下重新执行脚本的解决方案
在Next.js中使用<Link>标签进行SPA导航时,页面切换不会触发全局脚本重新执行,仅首次加载或刷新页面时脚本才会运行;而普通<a>标签会重载页面,脚本能正常执行。以下是保留SPA特性同时实现脚本重新执行的几种方法:
两种导航方式对比
SPA导航(不刷新页面)
<Link href="/page1"> <a>Page 1</a> </Link> <Link href="/page2"> <a>Page 2</a> </Link>
普通导航(刷新页面)
<a href="/page1">Page 1</a> <a href="/page2">Page 2</a>
当前脚本加载组件
通过MyScripts组件加载脚本,其中onReady回调会在每次页面切换时触发:
export default const MyScripts = () => { return ( <Script strategy="afterInteractive" type="module" src="/scripts/myScript.js" onReady={() => { console.log("Ready") }} /> ) }
解决方案
方案1:封装脚本核心逻辑,通过onReady调用
将脚本中的核心功能封装为可调用函数,在onReady中手动触发执行:
- 修改
myScript.js,抽出核心逻辑:
// /scripts/myScript.js export const initMyScript = () => { // 原脚本的核心逻辑,比如初始化事件、渲染内容等 console.log("脚本核心逻辑执行"); }; // 首次加载自动执行 initMyScript();
- 在
MyScripts组件中导入并调用该函数:
import { initMyScript } from "/scripts/myScript.js"; export default const MyScripts = () => { return ( <Script strategy="afterInteractive" type="module" src="/scripts/myScript.js" onReady={() => { initMyScript(); // 每次页面切换时重新执行核心逻辑 }} /> ) }
方案2:监听路由切换事件重新加载脚本
利用Next.js的useRouter钩子监听routeChangeComplete事件,在路由切换完成后重新加载脚本:
import { useEffect } from 'react'; import { useRouter } from 'next/router'; export default const MyScripts = () => { const router = useRouter(); useEffect(() => { const reloadScript = () => { // 移除旧脚本,避免重复执行 const oldScript = document.querySelector('script[src="/scripts/myScript.js"]'); if (oldScript) oldScript.remove(); // 创建并加载新脚本 const newScript = document.createElement('script'); newScript.type = 'module'; newScript.src = '/scripts/myScript.js'; document.body.appendChild(newScript); }; // 首次加载执行一次 reloadScript(); // 监听路由切换事件 router.events.on('routeChangeComplete', reloadScript); // 组件卸载时移除监听 return () => { router.events.off('routeChangeComplete', reloadScript); }; }, [router]); return null; }
方案3:清理副作用后重新执行脚本
如果无法修改原脚本,可先清理脚本产生的副作用(比如绑定的事件、生成的DOM元素),再重新加载脚本:
import { useEffect } from 'react'; import { useRouter } from 'next/router'; export default const MyScripts = () => { const router = useRouter(); const loadAndInitScript = () => { // 清理旧副作用:示例为克隆元素移除绑定事件 document.querySelectorAll('.script-target').forEach(el => { const clone = el.cloneNode(true); el.replaceWith(clone); }); // 重新加载脚本 const script = document.createElement('script'); script.type = 'module'; script.src = '/scripts/myScript.js'; const oldScript = document.querySelector('script[src="/scripts/myScript.js"]'); if (oldScript) oldScript.remove(); document.body.appendChild(script); }; useEffect(() => { loadAndInitScript(); router.events.on('routeChangeComplete', loadAndInitScript); return () => router.events.off('routeChangeComplete', loadAndInitScript); }, [router]); return null; }
内容的提问来源于stack exchange,提问作者Dan P
相关产品推荐
相关产品推荐

