当你浏览 SvelteKit 应用时,你会创建历史记录条目。点击后退和前进按钮会遍历此条目列表,重新运行任何 `加载` 函数,并在必要时替换页面组件。
有时,在不导航的情况下创建历史记录条目很有用。*无需*导航。例如,您可能希望显示一个用户可以通过导航返回来关闭的模态对话框。这在移动设备上尤其有价值,因为在移动设备上,滑动手势通常比直接与 UI 交互更自然。在这些情况下,一个与历史记录条目*不相关*的模态可能会引起用户的挫败感,因为用户可能会尝试向后滑动以关闭它,却发现自己在错误的页面上。
SvelteKit 通过`pushState`和`replaceState`函数实现这一点,这些函数允许您在不进行导航的情况下将状态与历史记录条目关联。例如,要实现由历史记录驱动的模态:
```svelte
{#if page.state.showModal}
history.back()} />
{/if}
```
模态窗口可以通过返回操作(取消设置 `page.state.showModal`)或通过与之交互以触发 `close` 回调的方式来关闭,这将程序化地返回上一页。
## API
第一个参数是相对于当前 URL 的 URL,要保持在当前 URL,请使用`''`。
第二个参数是新的页面状态,可以通过[页面对象]($app-state#page)作为`page.state`访问。您可以通过声明一个[`App.PageState`](types#PageState)接口(通常在`src/app.d.ts`中)来使页面状态类型安全。
为设置页面状态而不创建新的历史记录条目,请使用`replaceState`代替`pushState`。
> \[!旧版\] 从 `$app/state` 添加了 `page.state` 到 SvelteKit 2.12。如果您使用的是更早的版本或使用 Svelte 4,请使用从 `$app/stores` 的 `$page.state` 代替。
##
加载数据以供路线使用
当进行浅层路由时,您可能希望在当前页面内渲染另一个 `+page.svelte`。例如,点击照片缩略图可以弹出详细视图,而无需导航到照片页面。
为此工作,您需要加载 `+page.svelte` 所期望的数据。一种方便的方法是在一个 `` 元素的 `click` 处理器中使用 [`preloadData`]($app-navigation#preloadData)。如果该元素(或其父元素)使用了 [`data-sveltekit-preload-data`](link-options#data-sveltekit-preload-data),则数据已经被请求,并且 `preloadData` 将重用该请求。
```svelte
{#each data.thumbnails as thumbnail}
{
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);
}
}}
>
{/each}
{#if page.state.selected}
history.back()}>
{/if}
```
##
注意事项
在服务器端渲染期间,`page.state`始终是一个空对象。对于用户首次访问的页面也是如此——如果用户刷新页面(或从另一个文档返回),状态将*不会*应用,直到他们进行导航。
浅层路由是一个需要 JavaScript 才能工作的功能。使用时请谨慎,并尝试考虑在 JavaScript 不可用时的合理回退行为。