浅路由
在 SvelteKit 应用中导航时,您会创建历史记录条目。点击后退和前进按钮会遍历此条目列表,重新运行任何load
函数并根据需要替换页面组件。
有时,在不导航的情况下创建历史记录条目也很有用。例如,您可能希望显示一个模态对话框,用户可以通过向后导航将其关闭。这在移动设备上特别有用,因为滑动手势通常比直接与 UI 交互更自然。在这些情况下,未与历史记录条目关联的模态可能会成为一种挫败感,因为用户可能会尝试通过向后滑动来关闭它,却发现自己到了错误的页面。
SvelteKit 通过pushState
和replaceState
函数实现了这一点,这些函数允许您将状态与历史记录条目关联而不进行导航。例如,要实现一个由历史记录驱动的模态
<script>
import { pushState } from '$app/navigation';
import { page } from '$app/stores';
import Modal from './Modal.svelte';
function showModal() {
pushState('', {
showModal: true
});
}
</script>
{#if $page.state.showModal}
<Modal close={() => history.back()} />
{/if}
可以通过向后导航(取消设置$page.state.showModal
)或通过以某种方式与之交互来关闭模态,从而导致close
回调运行,这将以编程方式向后导航。
API
pushState
的第一个参数是 URL,相对于当前 URL。要保留在当前 URL 上,请使用''
。
第二个参数是新的页面状态,可以通过页面存储作为$page.state
访问。您可以通过声明一个App.PageState
接口(通常在src/app.d.ts
中)来使页面状态类型安全。
要设置页面状态而不创建新的历史记录条目,请使用replaceState
而不是pushState
。
加载路由的数据
在使用浅路由时,您可能希望在当前页面内渲染另一个+page.svelte
。例如,点击照片缩略图可以在不导航到照片页面的情况下弹出详细信息视图。
为了使此方法有效,您需要加载+page.svelte
期望的数据。一种方便的方法是在<a>
元素的click
处理程序中使用preloadData
。如果元素(或父元素)使用data-sveltekit-preload-data
,则数据将已被请求,并且preloadData
将重用该请求。
<script>
import { preloadData, pushState, goto } from '$app/navigation';
import { page } from '$app/stores';
import Modal from './Modal.svelte';
import PhotoPage from './[id]/+page.svelte';
let { data } = $props();
</script>
{#each data.thumbnails as thumbnail}
<a
href="/photos/{thumbnail.id}"
onclick={async (e) => {
if (innerWidth < 640 // bail if the screen is too small
|| e.shiftKey // or the link is opened in a new window
|| e.metaKey || e.ctrlKey // or a new tab (mac: metaKey, win/linux: ctrlKey)
// should also consider clicking with a mouse scroll wheel
) return;
// prevent navigation
e.preventDefault();
const { href } = e.currentTarget;
// run `load` functions (or rather, get the result of the `load` functions
// that are already running because of `data-sveltekit-preload-data`)
const result = await preloadData(href);
if (result.type === 'loaded' && result.status === 200) {
pushState(href, { selected: result.data });
} else {
// something bad happened! try navigating
goto(href);
}
}}
>
<img alt={thumbnail.alt} src={thumbnail.src} />
</a>
{/each}
{#if $page.state.selected}
<Modal onclose={() => history.back()}>
<!-- pass page data to the +page.svelte component,
just like SvelteKit would on navigation -->
<PhotoPage data={$page.state.selected} />
</Modal>
{/if}
注意事项
在服务器端渲染期间,$page.state
始终为空对象。用户访问的第一个页面也是如此——如果用户重新加载页面(或从另一个文档返回),则状态不会应用,直到他们进行导航。
浅路由是一个需要 JavaScript 才能工作的功能。在使用它时要小心,并尝试考虑在 JavaScript 不可用时合理的回退行为。