Nuxt.js SSR如何提前读取localStorage设置主题避免渲染闪烁
解决方案
核心原理
SSR场景下服务端无法访问浏览器localStorage,所以返回的初始页面默认是浅色主题,客户端hydration完成后才切换到用户保存的主题,时间差导致闪烁。我们只需要在页面开始渲染前,用最早执行的同步脚本先设置好html标签的data-theme属性,就能彻底避免闪烁。
实现步骤
注入前置内联脚本
在nuxt.config.js中配置head,把读取localStorage设置主题的脚本放在所有资源最前面执行:
// nuxt.config.js export default { head: { script: [ { innerHTML: ` (function() { // 优先读用户保存的主题,没有就默认light const savedTheme = localStorage.getItem('theme') || 'light'; document.documentElement.setAttribute('data-theme', savedTheme); })(); `, type: 'text/javascript' } ], // 必须加这个配置,避免脚本内容被转义 __dangerouslyDisableSanitizers: ['script'] } }
调整布局初始值
修改默认布局的data初始化逻辑,直接读取前置脚本已经设置好的html属性作为初始主题值,避免二次修改:
// 默认布局的script部分 export default { data: function () { return { // 客户端侧读已设置的主题,服务端渲染时用默认值不影响 theme: process.client ? document.documentElement.getAttribute('data-theme') : "light", }; }, // 剩下的head、methods、created等逻辑保持你原来的写法不变即可 head() { return { htmlAttrs: { "data-theme": this.theme, }, }; }, beforeMount() { // 这里原来的读取逻辑可以删掉了,前置脚本已经帮你做好了 }, methods: { setTheme(theme) { this.theme = theme; localStorage.setItem("theme", theme); }, }, created() { this.$nuxt.$on("changeTheme", (theme) => { this.setTheme(theme); }); }, }
注意事项
这个方案完全不需要阻止页面渲染,内联脚本是浏览器解析HTML时最先执行的同步代码,此时页面还没有开始渲染任何内容,修改data-theme不会产生视觉上的切换,也就不会有闪烁问题。后续用户手动切换主题的逻辑完全不受影响,切换时保存的主题值下次打开页面时会被前置脚本直接读取生效。
内容的提问来源于stack exchange,提问作者Destaq
相关产品推荐
相关产品推荐

