跳至主要内容

高级

浅层路由

在 GitHub 上编辑此页面

在 SvelteKit 应用中导航时,您会创建历史记录条目。单击后退和前进按钮将遍历此条目列表,重新运行任何 load 函数,并根据需要替换页面组件。

有时,创建进行导航的历史记录条目非常有用。例如,您可能希望显示一个模态对话框,用户可以通过导航返回来关闭该对话框。这在移动设备上尤其有价值,因为滑动操作通常比直接与 UI 交互更自然。在这些情况下,与历史记录条目关联的模态对话框可能会令人沮丧,因为用户可能会向后滑动以尝试关闭它,结果却发现自己进入了错误的页面。

SvelteKit 通过 pushStatereplaceState 函数实现了这一点,这些函数允许您将状态与历史记录条目关联,而无需进行导航。例如,要实现一个历史记录驱动的模态对话框

+page.svelte
<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.svelte
<script lang="ts">
	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 将重用该请求。

src/routes/photos/+page.svelte
<script>
	import { preloadData, pushState, goto } from '$app/navigation';
	import { page } from '$app/stores';
	import Modal from './Modal.svelte';
	import PhotoPage from './[id]/+page.svelte';

	export let data;
</script>

{#each data.thumbnails as thumbnail}
	<a
		href="/photos/{thumbnail.id}"
		on:click={async (e) => {
			// bail if opening a new tab, or we're on too small a screen
			if (e.metaKey || innerWidth < 640) 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 on:close={() => history.back()}>
		<!-- pass page data to the +page.svelte component,
			 just like SvelteKit would on navigation -->
		<PhotoPage data={$page.state.selected} />
	</Modal>
{/if}
src/routes/photos/+page.svelte
<script lang="ts">
	import { preloadData, pushState, goto } from '$app/navigation';
	import { page } from '$app/stores';
	import Modal from './Modal.svelte';
	import PhotoPage from './[id]/+page.svelte';
	
	export let data;
</script>

{#each data.thumbnails as thumbnail}
	<a
		href="/photos/{thumbnail.id}"
		on:click={async (e) => {
			// bail if opening a new tab, or we're on too small a screen
			if (e.metaKey || innerWidth < 640) 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 on:close={() => 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 不可用的情况下明智的回退行为。

上一个 快照
下一个 打包