跳至主要內容

淺層路由

當您在 SvelteKit 應用程式中導覽時,您會建立歷史記錄項目。點擊「上一頁」和「下一頁」按鈕會瀏覽此項目清單,重新執行任何 load 函式,並在必要時替換頁面元件。

有時,建立導覽的歷史記錄項目會很有用。例如,您可能想要顯示一個模態對話框,使用者可以透過返回來關閉它。這在行動裝置上尤其重要,因為滑動手勢通常比直接與 UI 互動更自然。在這些情況下,與歷史記錄項目沒有關聯的模態可能會令人感到沮喪,因為使用者可能會嘗試向後滑動以關閉它,卻發現自己到了錯誤的頁面。

SvelteKit 使用 pushStatereplaceState 函式使這成為可能,這些函式允許您將狀態與歷史記錄項目相關聯,而無需導覽。例如,要實作歷史記錄驅動的模態

+page
<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 將重複使用該請求。

src/routes/photos/+page
<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 不可用的情況下考慮合理的後備行為。

在 GitHub 上編輯此頁面

上一個 下一個