Nuxt 3 SSR模式下能否实现首页初始站点加载器?
在Nuxt 3 SSR模式下实现首页首次访问专属加载器
核心结论
完全可以实现,不需要切换到CSR,也不会因为hydration过程无法完成这个需求。
实现逻辑
首次访问首页时,Nuxt会通过SSR直接输出完整HTML到客户端。我们可以把加载器直接嵌入这份初始HTML中,等客户端完成Vue应用的hydration(挂载)后,再隐藏并移除加载器即可。路由间导航是客户端内部跳转,不会重新加载整个页面,所以加载器只会在首次访问首页时出现,天然符合需求。
具体实现步骤
1. 定制Nuxt初始HTML模板
在项目根目录创建app.html(如果没有的话),在<body>中先插入加载器的结构和样式,再放置Nuxt渲染的应用内容:
<!DOCTYPE html> <html {{ HTML_ATTRS }}> <head {{ HEAD_ATTRS }}> {{ HEAD }} <style> #initial-loader { position: fixed; inset: 0; background-color: #ffffff; display: flex; align-items: center; justify-content: center; z-index: 9999; transition: opacity 0.3s ease; } .spinner { width: 48px; height: 48px; border: 4px solid #e0e0e0; border-top-color: #2563eb; border-radius: 50%; animation: spin 1.2s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } </style> </head> <body {{ BODY_ATTRS }}> <!-- 仅在首页添加加载器 --> <% if (route.path === '/') { %> <div id="initial-loader"> <div class="spinner"></div> </div> <% } %> {{ APP }} </body> </html>
2. 在客户端挂载完成后移除加载器
创建一个Nuxt插件,监听应用挂载完成的事件,移除加载器:
在plugins/initial-loader.ts中写入:
export default defineNuxtPlugin(() => { if (process.client) { onMounted(() => { const loader = document.getElementById('initial-loader') if (loader) { // 添加淡出动画后移除 loader.style.opacity = '0' setTimeout(() => loader.remove(), 300) } }) } })
3. 额外校验(可选)
如果需要确保仅首次访问触发(比如用户刷新其他页面时不显示),可以结合localStorage做标记:
修改插件代码:
export default defineNuxtPlugin(() => { if (process.client) { onMounted(() => { const loader = document.getElementById('initial-loader') const hasVisited = localStorage.getItem('has-visited-home') if (loader && !hasVisited) { loader.style.opacity = '0' setTimeout(() => loader.remove(), 300) localStorage.setItem('has-visited-home', 'true') } else if (loader) { loader.remove() } }) } })
为什么这个方案可行?
加载器是SSR直接输出到初始HTML的,客户端打开页面时会立即显示,不需要等待JS加载或hydration完成。当Vue完成hydration并挂载应用后,再通过客户端代码移除加载器,完全绕开了hydration对加载器显示的限制,同时严格遵循SSR模式,不需要切换到CSR。
内容的提问来源于stack exchange,提问作者Thomas James Thorstensson
相关产品推荐
相关产品推荐

