Svelte条件渲染异常:登录页Header与Drawer短暂显示后消失
问题:SvelteKit中Login页面加载时Header和Drawer短暂显示后消失
我在Svelte项目里有个login页面,全局默认展示Drawer和Header,但想访问login页时隐藏这俩元素。于是在+layout.svelte里加了条件判断:用$app/stores的page获取当前路径,和禁用页面数组比对后,通过visibleDrawer、visibleHeader控制显示。但加载login页时,Header和Drawer会先闪一下再消失,这是为啥?
我的代码如下:
<script> import {page} from '$app/stores'; import "../app.css"; import Alert from "../lib/components/Alert.svelte"; import SidebarMenu from "../lib/layout/SidebarMenu.svelte"; import {onMount} from "svelte"; let currentPage; let visibleDrawer = true; let visibleHeader = true; const noDrawerPages = [ "pos", "login", ]; const noHeaderPages = [ "login", ]; onMount(() => { visibleDrawer = displayDrawer(); visibleHeader = displayHeader(); console.log("displace drawer", visibleDrawer) console.log("visible headers", visibleHeader) }); const displayDrawer = () => { const strippedPageName = currentPage.replace("/", ""); return !noDrawerPages.includes(strippedPageName); } const displayHeader = () => { const strippedPageName = currentPage.replace("/", ""); return !noHeaderPages.includes(strippedPageName); } $: currentPage = $page.url.pathname; $: showDrawerClass = visibleDrawer ? "drawer lg:drawer-open" : ""; </script> <div id="app"> <div class=" { showDrawerClass }" > <input id="main-drawer" type="checkbox" class="drawer-toggle"/> <div class="drawer-content flex flex-col"> <div class="text-gray-800 w-full"> {#if visibleHeader} <div>Header</div> {/if} </div> <main class="items-center min-h-screen justify-center w-full pt-12 p-12 border-accent-content/5 bg-gray-100"> <Alert /> <slot/> </main> </div> {#if visibleDrawer} <SidebarMenu /> {/if} </div> </div>
问题原因
核心问题出在初始值设置和响应式依赖缺失:
- 你给
visibleDrawer和visibleHeader设了初始值true,组件第一次渲染时会直接显示Header和Drawer; onMount是组件挂载到DOM后才执行的钩子,这时候才会计算并更新显示状态,所以会出现“先显示再消失”的闪烁;- 虽然你监听了
$page变化更新currentPage,但visibleDrawer和visibleHeader并没有和currentPage建立响应式关联,只有onMount会触发一次计算,逻辑不完整。
解决方案
把visibleDrawer和visibleHeader改成响应式变量,直接依赖currentPage,移除onMount里的逻辑:
修改后的代码:
<script> import {page} from '$app/stores'; import "../app.css"; import Alert from "../lib/components/Alert.svelte"; import SidebarMenu from "../lib/layout/SidebarMenu.svelte"; let currentPage; const noDrawerPages = [ "pos", "login", ]; const noHeaderPages = [ "login", ]; const displayDrawer = (pagePath) => { const strippedPageName = pagePath.replace("/", ""); return !noDrawerPages.includes(strippedPageName); } const displayHeader = (pagePath) => { const strippedPageName = pagePath.replace("/", ""); return !noHeaderPages.includes(strippedPageName); } $: currentPage = $page.url.pathname; $: visibleDrawer = displayDrawer(currentPage); $: visibleHeader = displayHeader(currentPage); $: showDrawerClass = visibleDrawer ? "drawer lg:drawer-open" : ""; </script> <div id="app"> <div class=" { showDrawerClass }" > <input id="main-drawer" type="checkbox" class="drawer-toggle"/> <div class="drawer-content flex flex-col"> <div class="text-gray-800 w-full"> {#if visibleHeader} <div>Header</div> {/if} </div> <main class="items-center min-h-screen justify-center w-full pt-12 p-12 border-accent-content/5 bg-gray-100"> <Alert /> <slot/> </main> </div> {#if visibleDrawer} <SidebarMenu /> {/if} </div> </div>
关键改动
- 移除
onMount钩子,不需要等到挂载后才计算显示状态; - 将
visibleDrawer和visibleHeader改为响应式变量,依赖currentPage自动更新; - 调整
displayDrawer和displayHeader函数,直接接收路径参数,逻辑更独立清晰。
这样修改后,组件初始渲染时就会根据当前路径计算出正确的显示状态,不会出现闪烁,同时路由切换时也能自动更新。
内容的提问来源于stack exchange,提问作者MrCujo
相关产品推荐
相关产品推荐

