Nuxt 3 - 如何在构建时在动态路线上添加元标记

问题描述 投票:0回答:4

我遇到的问题源于尝试将动态 OpenGraph 元标记应用到 Nuxt 3(以及扩展的 Vue 3)中动态生成的路线。

我尝试通过 Javascript 动态设置元标记 - 这似乎是 Nuxt 3 目前支持的唯一动态选项,但无济于事。显然,当开放图谱抓取工具请求页面时,它不会运行任何 JavaScript,这意味着我的元标记不会被应用。

我不想在服务器端渲染这些页面,保持它们动态生成是这个问题的重要组成部分。

到目前为止,我已经尝试使用

<Head>
标签,内容属性动态生成:

<Head>
  <Meta hid="og:url" property="og:url" :content="`https://my-site.com/{$route.path}`" />
</Head>

这会导致元标记正确应用,但仅在 Javascript 执行之后。正如我之前提到的,开放图网络抓取工具没有正确应用它。

我希望找到的解决方案是一种可以在构建时添加元标记的方法 - 这可能吗?或者还有我没有考虑的更好的解决方案吗?

typescript vue.js nuxt.js facebook-opengraph nuxtjs3
4个回答
0
投票

我相信你需要一个服务器来为你解决这个问题,所以页面应该是SSR,或者你需要在构建时(SSG)生成这些页面。

你也可以使用

useHead
可组合,但我认为你至少应该在这些页面使用 SSR 或 SSG:

useHead
的属性可以是动态的,接受引用、计算和反应属性。元参数还可以接受返回对象的函数,以使整个对象具有反应性。

在此处了解更多信息:https://nuxt.com/docs/api/composables/use-head

请检查:https://stackblitz.com/edit/nuxt-starter-51pnfj

并且您的代码中有一个错误。如果您使用组合 API,您的代码应该是这样的:

<Head>
  <Meta hid="og:url" property="og:url" :content="`https://my-site.com${route.path}`" />
</Head>

<script setup>
const route = useRoute();
</script>

如果您使用选项 API,您的代码应该是这样的:

<Head>
  <Meta hid="og:url" property="og:url" :content="`https://my-site.com${$route.path}`" />
</Head>

如果您没有将

ssr
设置为
false
,默认情况下它将为 true,或者如果您不希望所有页面都使用 SSR,我认为您可以使用混合渲染。所以结果会是这样的:


0
投票

您尝试过define-nuxt-route-middleware吗?它允许在构建时运行您的可组合函数。所以你的元应该已经正确应用于 SEO。相反,我在每个页面中使用 definePageMeta 而不是 useHead :

[某些页面].vue

<script setup>
definePageMeta({
  order: 1,
  label: "Perusahaan",
  title: "Perusahaan/Klien",
  description:
    "Kami memudahkan administrasi, semua absensi pekerja dapat dengan mudah dilacak riwayatnya serta memantau serta mengatur kehadiran pekerja dengan Geotagging dan pengelompokan area kerja untuk perusahaan atau klien",
  icon: "domain",
  transparent: true,
  image: "/perusahaan/invoice.png",
});
<script/>

并使用 useHead 一次,

中间件/meta.js

export default defineNuxtRouteMiddleware(async (to, from) => {
  let data = null,
    url = null,
    params = null;

  if (to.fullPath?.includes("berita") && to?.params?.slug) {
    url = new URL(`${useRuntimeConfig().public?.database}/Articles/get`);
    params = {
      jsonQuery: JSON.stringify({
        slug: to?.params?.slug,
      }),
      limit: 1,
    };
  } else if (to.fullPath?.includes("faq") && to?.params?.id) {
    url = new URL(`${useRuntimeConfig().public?.database}/FAQ/get`);
    params = {
      jsonQuery: JSON.stringify({
        _id: to?.params?.id,
      }),
      limit: 1,
    };
    // console.log(data);
  }

  if (url && params) {
    Object.keys(params).forEach((key) =>
      url.searchParams.append(key, params[key])
    );

    data = await fetch(url, {
      method: "GET",
    });

    data = await data?.json();
  }

  if (data?.success)
    data = data?.result?.[0];

  if (data || (to?.meta?.title && to?.meta?.description)) {
    useHead(
      useNuxtApp().$metaGenerator(
        data?.title || to?.meta?.title,
        data?.description || data?.excerpt || to?.meta?.description,
        to?.fullPath,
        data?.picture || to?.meta?.image,
        to?.meta?.keywords
      )
    );
  }
});

$metaGenerator(插件/index.js):

export default defineNuxtPlugin((nuxtApp) => {
  return {
    metaGenerator: (
        title,
        description,
        path,
        image,
        keywords,
        site = "@website"
      ) => {
        const defaultKeywords = [
          "lowongan kerja",
        ];
        if (Array.isArray(keywords)) keywords.concat(defaultKeywords);
        else keywords = defaultKeywords.concat(keywords || "");

        if (!image) {
          image = "/favicon.ico";
        }

        const url =
          `${useRuntimeConfig().hostname}${path}` ||
          useRuntimeConfig().hostname;

        return {
          title,
          meta: [
            {
              name: "description",
              content: description,
            },
            {
              rel: "canonical",
              href: url,
            },
            {
              rel: "amphtml",
              href: url,
            },
            {
              name: "keywords",
              content: keywords,
            },
            // google
            {
              itemprop: "name",
              content: title,
            },
            {
              itemprop: "description",
              content: description,
            },
            {
              itemprop: "image",
              content: image,
            },
            // twitter card
            {
              name: "twitter:card",
              content: "summary_large_image",
            },
            { name: "twitter:site", content: site },
            {
              name: "twitter:title",
              content: title,
            },
            {
              name: "twitter:description",
              content: description,
            },
            {
              name: "twitter:image",
              content: image,
            },
            {
              name: "twitter:image:alt",
              content: title,
            },
            {
              name: "twitter:url",
              content: url,
            },
            // Open Graph
            { property: "og:site_name", content: site },
            { property: "og:type", content: "website" },
            {
              property: "og:title",
              content: title,
            },
            {
              property: "og:description",
              content: description,
            },
            {
              property: "og:image",
              content: image,
            },
            {
              property: "og:url",
              content: url,
            },
            {
              property: "og:image:secure_url",
              content: image,
            },
            {
              property: "og:image:alt",
              content: title,
            },
          ],
          link: [
            {
              rel: "canonical",
              href: url,
            },
            {
              rel: "amphtml",
              href: url,
            },
          ],
        };
      },
  }
})

0
投票

useSeoMeta
对我有用,而
useHead
则不然。我试图使用以下代码更改描述元。

useSeoMeta({
  description: () => 'New meta description',
});

0
投票

我使用 useSeoMeta 它对我有用

<script setup lang="ts">
useSeoMeta({
  title: () => 'My Amazing Site',
  ogTitle: () => 'My Amazing Site',
  description: () => 'This is my amazing site, let me tell you all about it.',
  ogDescription: () => 'This is my amazing site, let me tell you all about it.',
  ogImage: () => 'https://example.com/image.png',
  twitterCard: () => 'summary_large_image',
})
</script>
© www.soinside.com 2019 - 2024. All rights reserved.