跳至主要內容

進階

淺層路由

在 GitHub 上編輯此頁面

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

有時,建立歷史記錄項目而不導覽會很有用。例如,您可能想顯示一個對話框,讓使用者可以透過導覽返回來關閉。這在行動裝置上特別有用,因為滑動手勢通常比直接與使用者介面互動更自然。在這些情況下,與歷史記錄項目關聯的對話框可能會造成困擾,因為使用者可能會向後滑動以嘗試關閉對話框,卻發現自己到了錯誤的頁面。

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 無法使用時,考慮合理的備援行為。

上一個 快照
下一個 封裝