Nuxt 3中如何修复基于滚动条件类的Hydration错误?
我有一个顶部Navbar组件,逻辑为:用户完全未滚动(Y偏移量=0)时不显示桌面端阴影,滚动距离越远阴影越大。相关代码如下:
滚动阴影类计算的Composable代码
export function getShadowClassBasedOnScrollingOffset( alwaysDisplayOnMobile: boolean = true, ): string { const { y } = useWindowScroll(); let classList = ""; if (alwaysDisplayOnMobile) { classList += "shadow "; } if (y.value < 5) { classList += "md:shadow-none"; return classList; } if (y.value < 10) { classList += "md:shadow"; return classList; } classList += "md:shadow-lg"; return classList; }
Navbar组件中使用方式
// Setup const getShadowClass = computed(() => { return props.displayShadow ? getShadowClassBasedOnScrollingOffset(true) : ""; });
<template> <div class="w-full bg-white | px-4 md:px-0 py-4 transition" :class="getShadowClass" > <!-- Navbar内容 --> </div> </template>
收到的Hydration警告
Hydration class Mismatch on
:
- rendered on server: class="w-full bg-white | px-4 md:px-0 py-4 transition shadow md:shadow-none"
- expected on client: class="w-full bg-white | px-4 md:px-0 py-4 transition shadow md:shadow-lg"
问题原因
服务端渲染时没有浏览器环境,useWindowScroll的y.value默认是0,因此服务端会渲染md:shadow-none类;但客户端初始化时,如果页面并非从顶部开始(比如用户刷新时处于滚动状态),y.value会是实际滚动值,导致客户端渲染的类与服务端不一致,触发Hydration不匹配警告。
修复方案
核心思路是让服务端和客户端初始渲染的类完全一致,服务端固定返回未滚动状态的类,客户端挂载后再根据实际滚动值更新类。
方案1:在组件中添加客户端状态判断
修改Navbar组件的setup逻辑,确保服务端返回与初始渲染一致的类:
import { ref, computed, onMounted } from 'vue'; // Setup const isClient = ref(false); onMounted(() => { // 标记客户端已挂载 isClient.value = true; }); const getShadowClass = computed(() => { if (!props.displayShadow) return ''; // 服务端渲染时返回固定的未滚动状态类 if (!isClient.value) { return 'shadow md:shadow-none'; } // 客户端挂载后再根据滚动计算类 return getShadowClassBasedOnScrollingOffset(true); });
方案2:修改Composable,加入客户端环境判断
直接在Composable中判断是否处于客户端环境,服务端时返回固定类:
export function getShadowClassBasedOnScrollingOffset( alwaysDisplayOnMobile: boolean = true, ): string { const isClient = typeof window !== 'undefined'; const { y } = useWindowScroll(); let classList = ""; if (alwaysDisplayOnMobile) { classList += "shadow "; } // 服务端时直接返回未滚动状态类 if (!isClient) { classList += "md:shadow-none"; return classList.trim(); } if (y.value < 5) { classList += "md:shadow-none"; return classList.trim(); } if (y.value < 10) { classList += "md:shadow"; return classList.trim(); } classList += "md:shadow-lg"; return classList.trim(); }
两种方案都能确保服务端和客户端初始渲染的类一致,Hydration完成后客户端再根据实际滚动状态更新阴影类,既保留SSR的优势,又解决了警告问题。
内容的提问来源于stack exchange,提问作者xTheWolf
相关产品推荐
相关产品推荐

