NextJS 14(appDir):如何在<head>添加脚本并路由变化时重跑
在Next.js 14 App Router中实现路由变化时重新执行内的广告脚本
核心问题分析
你之前用useEffect或Next.js官方Script组件没达到效果,本质是因为App Router的客户端导航不会触发页面重载,普通挂载逻辑只会执行一次,且Script组件默认不会在路由切换时重新加载/执行脚本。
解决方案:监听路由变化+动态脚本管理
创建一个客户端组件,通过usePathname监听路由切换,每次路由变化时重新注入并执行广告脚本,同时处理重复脚本的问题。
步骤1:创建广告脚本组件
新建components/AdScripts.tsx(必须加上'use client'指令):
'use client'; import { useEffect, useRef } from 'react'; import { usePathname } from 'next/navigation'; export default function AdScripts() { const pathname = usePathname(); // 保存外部脚本引用,用于路由变化时清理 const externalAdScriptRef = useRef<HTMLScriptElement | null>(null); useEffect(() => { // 1. 清理旧的外部脚本(避免重复加载) if (externalAdScriptRef.current) { externalAdScriptRef.current.remove(); externalAdScriptRef.current = null; } // 2. 注入外部广告脚本 const externalScript = document.createElement('script'); externalScript.src = 'https://example.com/third-party.js'; externalScript.async = true; document.head.appendChild(externalScript); externalAdScriptRef.current = externalScript; // 3. 定义内联广告脚本执行逻辑 const runInlineAdCode = () => { // 替换成你的实际内联广告代码 // 示例:如果是第三方广告初始化/刷新逻辑 // window.adPlatform?.init(); // window.adPlatform?.refreshAds(); console.log('执行内联广告脚本 - 当前路由:', pathname); }; // 4. 确保外部脚本加载完成后执行内联代码(可选,根据脚本依赖调整) externalScript.onload = runInlineAdCode; // 如果外部脚本加载失败,也尝试执行(按需调整) externalScript.onerror = runInlineAdCode; // 路由切换前的清理逻辑 return () => { if (externalAdScriptRef.current) { externalAdScriptRef.current.remove(); externalAdScriptRef.current = null; } }; }, [pathname]); // 依赖pathname,路由变化时重新执行 return null; // 组件无UI输出 }
步骤2:在根布局中引入组件
修改app/layout.tsx,将组件放入<head>标签内:
import AdScripts from '@/components/AdScripts'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="zh-CN"> <head> <AdScripts /> {/* 其他head元数据、样式等 */} </head> <body>{children}</body> </html> ); }
关键注意事项
- 避免重复脚本:用
useRef保存外部脚本实例,每次路由变化先移除旧脚本再添加新的,防止多次加载导致的冲突。 - 脚本依赖顺序:如果内联代码依赖外部脚本的全局变量,一定要通过
onload事件确保外部脚本加载完成后再执行内联逻辑。 - 广告平台适配:不同广告平台的刷新逻辑不同,比如Google AdSense需要调用
googletag.pubads().refresh(),请根据实际平台文档调整内联代码。
内容的提问来源于stack exchange,提问作者Prajjwal Rajput
相关产品推荐
相关产品推荐

