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

Nuxt3首页index.vue无法SSR渲染问题求助

Nuxt3首页index.vue无法SSR渲染,其他页面正常的问题排查与解决

我使用Nuxt3,通过Server目录搭建了自定义API。但遇到问题:pages文件夹下的index.vue作为首页,内容无法以SSR方式渲染;但将该页面内容移至任意命名的新页面(如xxx.vue)时,相同数据可正常SSR渲染。

目录结构

--pages
  --index.vue

index.vue代码

<template>
  <NuxtLayout name="moviedetails">
    <v-container>
      <v-card class="my-4" color="transparent" variant="flat">
        <main-news-slider class="mt-4" />
        <v-container>
          <v-card color="transparent" flat>
            <div id="AADIV33"></div>
          </v-card>
        </v-container>
        <!-- <ClientOnly> -->
        <IGNSlider :data="ignIndex.data" />
        <!-- </ClientOnly> -->
        <AnimeSlider :season="getCurrentSeason()" />
        <v-card-actions class="justify-center my-4">
          <v-btn-toggle
            color="primary"
            mandatory
            density="compact"
            v-model="trendTime"
            rounded="xl"
          >
            <v-btn value="week" size="small" density="compact"
              >هذا الأسبوع</v-btn
            >
            <v-btn value="day" size="small" density="compact">اليوم</v-btn>
          </v-btn-toggle>
        </v-card-actions>
        <swiper-trends-slider
          :swiperData="trendTime == 'day' ? todayTrendsData : weekTrendsData"
        >
        </swiper-trends-slider>
      </v-card>
      <v-locale-provider rtl>
        <v-card
          v-for="genres in allGenres"
          class="my-4"
          color="transparent"
          variant="flat"
        >
          <v-card-title class="mt-4"> {{ genres?.item?.title }} </v-card-title>
          <swiper-geners-sliders
            :swiperGenederData="genres?.data?.results"
            :swiperBreakPoints="genersBreakPoints"
            :mediaDataId="genres?.item"
          >
          </swiper-geners-sliders>
        </v-card>
      </v-locale-provider>
    </v-container>
  </NuxtLayout>
</template>

<script setup>
import { getCurrentSeason } from "~~/common/commonFuntions";
import IGNSlider from "~~/components/IGNSlider.vue";

const trendTime = ref("day");

const genersBreakPoints = ref({
  640: {
    slidesPerView: 2,
    spaceBetween: 20,
  },
  768: {
    slidesPerView: 4,
    spaceBetween: 20,
  },
  1024: {
    slidesPerView: 6,
    spaceBetween: 20,
  },
});

const { data: todayTrendsData } = await useFetch(
  `/api/trendslider/day?type=day`
);
const { data: weekTrendsData } = await useFetch(
  `/api/trendslider/day?type=week`
);

const randid = function generateRandomId() {
  return Math.floor(Math.random() * 900000) + 100000 + "";
};

const { data: ignIndex } = await useFetch(`/api/ign/home?${randid}=${randid}`);
console.log(ignIndex);
const { data: allGenres } = await useFetch("/api/genres");

const returnMainPaegAds = () => {
  /* header_ads_section */ var k = decodeURIComponent(document.cookie),
    ca = k.split(";"),
    psc = "";
  ca;
  for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == " ") c = c.substring(1);
    if (c.indexOf("adcapban") == 0)
      psc +=
        (psc == "" ? "" : ",") + c.replace("adcapban", "").replace("=", ",");
  }
  var s = document.createElement("script");
  s.src =
    "https://adsmanager.trexqr.com/ser.php?t=AADIV33" +
    String.fromCharCode(38) +
    "f=33" +
    String.fromCharCode(38) +
    "psc=" +
    psc;
  s;
  return s.src;
};

const showScript = ref(false);

const nuxt = useNuxtApp();

nuxt.hook("page:start", () => {
  showScript.value = false;
});

nuxt.hook("page:finish", () => {
  setTimeout(() => {
    showScript.value = true;
  }, 1000);
});

const route = useRoute();

useHead({
  script: [
    {
      src: () => (showScript.value == true ? returnMainPaegAds() : ""),
      tagPosition: "head", // valid options are: 'head' | 'bodyClose' | 'bodyOpen'
    },
  ],
});

// definePageMeta({
//   layout: "moviedetails",
//   key: (route) => route.fullPath,
// });
</script>

<style>
.ck-content * {
  color: black;
}
</style>

nuxt.config配置

// https://nuxt.com/docs/api/configuration/nuxt-config

import vuetify from "vite-plugin-vuetify";
import { createResolver } from "@nuxt/kit";

const { resolve } = createResolver(import.meta.url);

export default defineNuxtConfig({
  ssr: true,
  modules: ["nuxt-swiper", '@pinia/nuxt', 'nuxt-delay-hydration', "nuxt-lodash"],
  delayHydration: {
    idleCallbackTimeout: 2000
  },
  runtimeConfig: {
    TMDBKEY: process.env.NUXT_TMDBKEY,
    SCRIPT_KEY: process.env.NUXT_SCRIPT,
    PPKEY: "123",
    public: {
      TMDBKEY: "*****",
    },
  },
  css: [
    "vuetify/lib/styles/main.sass",
    "@mdi/font/css/materialdesignicons.min.css",
    "@/assets/main.scss",
    "@vuepic/vue-datepicker/dist/main.css"
  ],
  build: {
    transpile: ["vuetify"],
  },

  vite: {
    define: {
      "process.env.DEBUG": false,
    },
  },
  app: {
    head: {
      titleTemplate: "%s - Aflam.vip",
      title: "Aflam.vip",
      meta: [
        { charset: "utf-8" },
        {
          name: "viewport",
          content:
            "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0",
        },
        { name: "msapplication-TileImage", content: "telephone=no" },
        { name: "propeller", content: "*****" },
      ],
      script: [
      ],
      style: [],
      noscript: []
    },
  },
  plugins: [],
  imports: {
    dirs: ['./stores'],
  },
  pinia: {
    autoImports: ['defineStore', 'acceptHMRUpdate'],
  },
});

问题排查与解决方法

1. 排除nuxt-delay-hydration模块的影响

你启用了nuxt-delay-hydration模块,该模块会延迟页面 hydration,可能导致首页看起来未完成SSR。可以针对首页禁用该功能:

// nuxt.config.ts
export default defineNuxtConfig({
  delayHydration: {
    excludeRoutes: ['/'] // 首页跳过延迟 hydration
  }
})

或者临时移除该模块,验证是否是它导致的问题。

2. 修复客户端API在SSR阶段的执行错误

returnMainPaegAds函数中直接使用了document.cookie,这是客户端专属API,在SSR阶段执行会抛出错误,中断首页的SSR渲染。需要限制该函数仅在客户端运行:

const returnMainPaegAds = () => {
  if (process.server) return '' // 服务端直接返回空,避免执行客户端代码
  var k = decodeURIComponent(document.cookie),
    ca = k.split(";"),
    psc = "";
  for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == " ") c = c.substring(1);
    if (c.indexOf("adcapban") == 0)
      psc +=
        (psc == "" ? "" : ",") + c.replace("adcapban", "").replace("=", ",");
  }
  return `https://adsmanager.trexqr.com/ser.php?t=AADIV33&f=33&psc=${psc}`
};

更推荐使用Nuxt3提供的useCookieAPI,它支持跨服务端和客户端操作:

const adcapban = useCookie('adcapban')
const returnMainPaegAds = () => {
  const psc = adcapban.value ? adcapban.value.replace("=", ",") : ""
  return `https://adsmanager.trexqr.com/ser.php?t=AADIV33&f=33&psc=${psc}`
};

3. 启用页面唯一key配置

取消注释代码中definePageMeta的配置,给首页设置唯一路由key,避免路由复用导致的渲染异常:

definePageMeta({
  layout: "moviedetails",
  key: (route) => route.fullPath
});

4. 清除Nuxt缓存并重启服务

首页可能被缓存为客户端渲染版本,执行以下操作清除缓存:

  • 删除项目根目录下的.nuxt和.output文件夹
  • 运行npx nuxi clean命令
  • 重启开发服务器

5. 检查自定义API的请求状态

确保首页调用的/api/trendslider/day、/api/ign/home、/api/genres接口在服务端正常返回数据。可以在useFetch中添加错误处理,排查请求问题:

const { data: todayTrendsData, error: todayError } = await useFetch(`/api/trendslider/day?type=day`)
if (todayError.value) {
  console.error('今日趋势接口请求失败:', todayError.value)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:44:55