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

Next.js src/app目录结构下如何在head标签中添加脚本?

在Next.js App Router(src/app结构)中为特定页面添加内容的方法

1. 使用Metadata API(官方推荐)

App Router下官方主推用Metadata API管理标签,支持静态定义和动态生成,针对特定页面,直接在对应页面的page.tsx/page.jsx文件里导出配置即可。

静态Metadata配置

如果不需要动态数据,直接导出metadata对象就能添加脚本、meta标签、样式链接等:

// src/app/about/page.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: '关于我们',
  description: '这是站点的关于页面',
  // 自定义meta标签
  other: {
    'custom-tag': '自定义内容',
  },
  // 添加外部脚本
  scripts: [
    // 外部脚本,默认注入到head
    {
      src: 'https://example.com/script.js',
      strategy: 'beforeInteractive', // 可选加载策略:beforeInteractive/afterInteractive/lazyOnload
    },
    // 内联脚本
    {
      dangerouslySetInnerHTML: {
        __html: `console.log('页面加载时执行的内联脚本')`,
      },
    },
  ],
  // 添加外部样式
  links: [
    {
      rel: 'stylesheet',
      href: 'https://example.com/custom-style.css',
    },
  ],
};

export default function AboutPage() {
  return <div>关于页面内容</div>;
}

动态Metadata配置

如果需要根据页面参数(比如文章slug)动态生成内容,用generateMetadata函数:

// src/app/post/[slug]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next';

type Props = {
  params: { slug: string };
};

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  // 根据slug获取文章数据
  const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(res => res.json());

  // 可以继承父布局的metadata
  const parentImages = (await parent).openGraph?.images || [];

  return {
    title: post.title,
    description: post.excerpt,
    scripts: [
      {
        src: `/scripts/post-${params.slug}.js`,
        strategy: 'afterInteractive',
      },
    ],
    openGraph: {
      images: [...parentImages, post.coverUrl],
    },
  };
}

export default function PostPage({ params }: Props) {
  return <div>文章内容:{params.slug}</div>;
}

2. 使用Next.js Script组件

如果需要更灵活的脚本加载控制,用next/script组件,它会自动把脚本注入到或,根据设置的strategy调整时机:

// src/app/contact/page.tsx
import Script from 'next/script';

export default function ContactPage() {
  return (
    <div>
      <h1>联系我们</h1>
      {/* 注入到head的脚本,beforeInteractive策略会在页面交互前加载 */}
      <Script
        src="https://example.com/contact-form-script.js"
        strategy="beforeInteractive"
        id="contact-script"
      />
      {/* 内联脚本,注入到head */}
      <Script
        id="inline-contact-handler"
        strategy="afterInteractive"
      >
        {`
          document.getElementById('contact-form').addEventListener('submit', (e) => {
            e.preventDefault();
            console.log('表单提交逻辑触发');
          });
        `}
      </Script>
      <form id="contact-form">
        {/* 表单内容 */}
      </form>
    </div>
  );
}

加载策略说明:

  • beforeInteractive:适合核心脚本,在页面HTML发送到客户端前注入到head
  • afterInteractive:页面可交互后立即加载,适合非核心但需快速执行的脚本
  • lazyOnload:浏览器空闲时加载,适合非紧急脚本

3. 兼容方式:直接使用next/head

虽然官方推荐Metadata API,但也可以用next/head组件快速实现,不过需要标记为客户端组件(加'use client'指令):

// src/app/faq/page.tsx
'use client';
import Head from 'next/head';

export default function FaqPage() {
  return (
    <>
      <Head>
        <title>常见问题</title>
        <meta name="keywords" content="FAQ,帮助中心,问题解答" />
        <script src="https://example.com/faq-script.js" async></script>
        <link rel="preconnect" href="https://fonts.googleapis.com" />
      </Head>
      <div>常见问题内容</div>
    </>
  );
}

注意:这种方式适合旧代码迁移,但Metadata API能更好地适配App Router的静态生成、服务器组件等特性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:07:02