在初始渲染时将Svelte组件变量设为localStorage/全局变量值
在Svelte/SvelteKit中避免初始值闪烁,同步localStorage到组件初始值
问题场景
我使用Svelte + SvelteKit开发项目时,需要根据用户保存在localStorage中的历史值设置组件内变量的初始值。目前实现的方式是在页面加载后赋值:
let foo = false; if (browser) { foo = localStorage.collapsed === 'true' }
但这段代码会在页面加载完成后执行,导致初始值闪烁(先显示默认的false状态,再切换为localStorage保存的值)。
我也尝试过用<svelte:head>在页面渲染前获取localStorage值:
<svelte:head> <script> if (localStorage.foo === 'true') { window.foo = true; } </script> </svelte:head>
但不知道如何将这个全局变量同步到组件变量中,而通过CSS给documentElement或body添加类的方式并不适用于当前场景。
解决方案
1. 组件顶层直接同步取值(最简单的方案)
利用Svelte客户端组件初始化时顶层代码同步执行的特性,直接在变量初始化阶段结合browser判断读取localStorage,无需等到页面加载完成:
<script> import { browser } from '$app/environment'; // 初始化时直接取值,避免闪烁 let foo = browser ? localStorage.getItem('collapsed') === 'true' : false; </script>
这种方式会在组件DOM渲染前完成赋值,完全避免闪烁问题。
2. 同步<svelte:head>中的全局变量
如果坚持使用<svelte:head>的思路,可以在组件顶层直接读取window上的全局变量,同样结合browser判断确保只在客户端执行:
<script> import { browser } from '$app/environment'; // 读取<svelte:head>中设置的全局变量,默认值为false let foo = browser ? window.foo ?? false : false; </script> <svelte:head> <script> // 优先于组件DOM渲染执行 window.foo = localStorage.getItem('foo') === 'true'; </script> </svelte:head>
Svelte会优先渲染<svelte:head>中的内容,因此组件顶层代码读取window.foo时已经有值。
3. 页面级组件使用SvelteKit的load函数
如果是页面组件(+page.svelte),可以通过+page.js的load函数在客户端读取localStorage,并将值传递给组件:
// +page.js import { browser } from '$app/environment'; export function load() { if (browser) { return { collapsed: localStorage.getItem('collapsed') === 'true' }; } // 服务端返回默认值 return { collapsed: false }; }
然后在页面组件中接收并使用该值:
<script> export let data; let foo = data.collapsed; </script>
这种方式适合页面级的状态管理,能保证组件初始化时就拿到正确的值,彻底避免闪烁。
内容的提问来源于stack exchange,提问作者Zach Saucier
相关产品推荐
相关产品推荐

