SvelteKit布局中{#key}包裹的<slot>页面过渡未延迟如何解决?
解决SvelteKit页面过渡时内容提前更新的问题
问题核心在于SvelteKit的路由导航会即时替换<slot>内容,和{#key}的过渡触发同步,导致旧内容还未完成淡出,新内容就已显示。要实现「旧页面淡出→新页面淡入」的顺序,需拦截导航流程,等待过渡完成后再加载新页面。
修改+layout.svelte代码如下:
<script lang="ts"> import '$lib/style.css'; import { page } from '$app/stores'; import { fade } from 'svelte/transition'; import { goto, onNavigate } from '$app/navigation'; import { writable } from 'svelte/store'; // 延迟更新页面路径,等待过渡完成 const currentPath = writable($page.url.pathname); let isTransitioning = false; onNavigate(async ({ from, to, cancel }) => { if (isTransitioning || from?.url.pathname === to?.url.pathname) return; // 阻止默认导航行为 cancel(); isTransitioning = true; // 触发旧内容淡出动画 currentPath.set(from.url.pathname); // 等待淡出动画完成(时长与out:fade配置一致) await new Promise(resolve => setTimeout(resolve, 1000)); // 执行导航并更新路径,触发新内容淡入 await goto(to.url.pathname); currentPath.set(to.url.pathname); isTransitioning = false; }); </script> <div class="page"> <div class="bar"> Sidebar <a href="/">Page 1</a> <a href="/page2">Page 2</a> </div> <div class="content-wrapper"> {#key $currentPath} <div class="content" in:fade={{ duration: 1000 }} out:fade={{ duration: 1000 }}> <div class="title"> {$currentPath} </div> <slot /> </div> {/key} </div> </div> <style global> .page { display: flex; flex-direction: row; box-sizing: border-box; width: 100vw; min-height: 100vh; } .bar { display: flex; flex-direction: column; width: 300px; color: white; background: black; } a { color: white; } .content-wrapper { flex-grow: 1; width: 100%; min-height: 100vh; position: relative; } .content { position: absolute; width: 100%; height: 100%; } .title { font-size: 2em; } </style>
关键修改说明:
- 新增
currentPath存储,用来延迟更新页面路径,避免路由即时替换slot内容 - 通过
onNavigate拦截默认导航,等待旧页面淡出动画完成后再执行实际导航 - 给
.content添加position: absolute,确保新旧页面过渡时不会互相挤压 - 移除
in:fade的delay配置,因为现在是旧页面完全淡出后才触发新页面淡入,无需额外延迟
修改后,导航时会先完成旧页面的淡出动画,再加载新页面并执行淡入,<slot>内容即可和标题同步正常过渡。
内容的提问来源于stack exchange,提问作者Orion31
相关产品推荐
相关产品推荐

