Next.js 15 App Router 中封装通用 JSON-LD 结构化数据组件

什么是结构化数据?

结构化数据是一种特殊格式的代码(通常是 JSON-LD),放在网页 <head><body> 中,用于帮助搜索引擎理解页面内容。

✅ 最常见的数据结构:JSON-LD(推荐)

Next.js 中可以这样插入:

import Head from 'next/head';

export default function ProductPage() {
  const productJsonLd = {
    "@context": "https://schema.org/",
    "@type": "Product",
    "name": "Apple iPhone 14",
    "image": ["https://example.com/iphone14.jpg"],
    "description": "The latest iPhone with A15 Bionic chip",
    "sku": "iphone14-128gb",
    "brand": {
      "@type": "Brand",
      "name": "Apple"
    },
    "offers": {
      "@type": "Offer",
      "url": "https://example.com/iphone14",
      "priceCurrency": "USD",
      "price": "799.00",
      "availability": "https://schema.org/InStock"
    }
  };

  return (
    <>
      <Head>
        <title>iPhone 14 - Buy Now</title>
        <script type="application/ld+json">
          {JSON.stringify(productJsonLd)}
        </script>
      </Head>
      <main>
        {/* 页面主要内容 */}
      </main>
    </>
  );
}

✅ 支持的类型(常见):

  • Article:博客文章、新闻文章
  • Product:商品页面
  • BreadcrumbList:面包屑导航
  • Organization:企业信息
  • FAQPage:问答页面
  • WebPage:通用网页
  • Event:活动页面
  • Recipe:食谱

👉 可参考:https://schema.org/docs/full.html

✅ 在 Next.js 中使用建议

  • 使用 <script type="application/ld+json"> 插入到 <head>(通过 next/head
  • 或者在 generateMetadata 中提供动态 SEO 信息
  • 注意不要拼错字段名,否则可能无效
  • 用 Google 的 Rich Results Test 工具检测效果

目标

  1. 在 App Router 中插入 JSON-LD Schema.org 数据结构(对 SEO 友好)
  2. 封装一个通用的 <StructuredData> 组件,支持多类型 Schema(Article/Product/FAQ等)
  3. 在页面中优雅地调用

🧩 1. 创建通用组件 <StructuredData />

📁 位置建议:components/StructuredData.tsx

'use client'

import React from 'react'

interface StructuredDataProps {
  data: Record<string, any>
}

const StructuredData: React.FC<StructuredDataProps> = ({ data }) => {
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{
        __html: JSON.stringify(data, null, 2),
      }}
    />
  )
}

export default StructuredData

dangerouslySetInnerHTML 是必须的,否则结构化数据不会生效。


📁 2. 在页面中使用

以博客文章详情页为例,路径为 app/blog/[slug]/page.tsx

// app/blog/[slug]/page.tsx
import { getBlogPostBySlug } from './data'
import { notFound } from 'next/navigation'
import StructuredData from '@/components/StructuredData'
import type { Metadata } from 'next'

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

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const post = await getBlogPostBySlug(params.slug)
  if (!post) return {}

  return {
    title: post.title,
    description: post.summary,
  }
}

export default async function Page({ params }: Props) {
  const post = await getBlogPostBySlug(params.slug)
  if (!post) return notFound()

  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": post.title,
    "description": post.summary,
    "author": {
      "@type": "Person",
      "name": post.author.name,
    },
    "datePublished": post.publishedAt,
    ...(post.updatedAt && { "dateModified": post.updatedAt }),
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": post.url,
    }
  }

  return (
    <>
      <StructuredData data={jsonLd} />
      <article className="prose">
        <h1>{post.title}</h1>
        <p>{post.publishedAt}</p>
        <div dangerouslySetInnerHTML={{ __html: post.html }} />
      </article>
    </>
  )
}

🔁 3. 多种类型结构化数据示例(可复用)

✅ Article 类型

const articleJsonLd = {
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "文章标题",
  "description": "文章摘要",
  "author": {
    "@type": "Person",
    "name": "作者名"
  },
  "datePublished": "2025-07-08",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://example.com/blog/slug"
  }
}

✅ Product 类型

const productJsonLd = {
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Apple iPhone 14",
  "image": ["https://example.com/iphone14.jpg"],
  "description": "The latest iPhone",
  "sku": "iphone14-128gb",
  "brand": {
    "@type": "Brand",
    "name": "Apple"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/iphone14",
    "priceCurrency": "USD",
    "price": "799.00",
    "availability": "https://schema.org/InStock"
  }
}

✅ FAQPage 类型

const faqJsonLd = {
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "如何注册账号?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "点击右上角注册按钮即可。"
      }
    },
    {
      "@type": "Question",
      "name": "如何联系客服?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "请拨打 400-123-4567。"
      }
    }
  ]
}

🧪 4. 验证结构化数据有效性

使用 Google 提供的工具:

  • ✅ Rich Results Test

https://search.google.com/test/rich-results

  • ✅ Schema Markup Validator

https://validator.schema.org/

小结:推荐实践

内容类型Schema.org 类型组件调用方法
博客文章Article<StructuredData data={articleJsonLd} />
商品Product<StructuredData data={productJsonLd} />
FAQFAQPage<StructuredData data={faqJsonLd} />
公司信息Organization<StructuredData data={orgJsonLd} />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值