進階
淺層路由
在 GitHub 上編輯此頁面在 SvelteKit 應用程式中導覽時,您會建立歷史記錄項目。按一下「上一步」和「下一步」按鈕會瀏覽此項目清單,重新執行任何 load
函式,並視需要更換頁面元件。
有時,建立歷史記錄項目而不導覽會很有用。例如,您可能想顯示一個對話框,讓使用者可以透過導覽返回來關閉。這在行動裝置上特別有用,因為滑動手勢通常比直接與使用者介面互動更自然。在這些情況下,未與歷史記錄項目關聯的對話框可能會造成困擾,因為使用者可能會向後滑動以嘗試關閉對話框,卻發現自己到了錯誤的頁面。
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}
<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
將會重複使用該要求。
<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}
<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 無法使用時,考慮合理的備援行為。