シャロールーティング
SvelteKit アプリケーション内を遷移すると、_履歴エントリ_が作成されます。戻るボタンと進むボタンをクリックすると、このエントリリストを辿り、必要に応じて `load` 関数を再実行し、ページコンポーネントを置き換えます。
遷移_せずに_履歴エントリを作成すると便利な場合があります。たとえば、ユーザーが戻ることで閉じることができるモーダルダイアログを表示したい場合があります。これは、UI を直接操作するよりもスワイプジェスチャの方が自然なモバイルデバイスで特に役立ちます。このような場合、履歴エントリに_関連付けられていない_モーダルは、ユーザーがそれを閉じようとして誤ってスワイプバックし、間違ったページに移動してしまう可能性があるため、フラストレーションの原因となる可能性があります。
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}
モーダルは、戻るボタンで遷移する(`$page.state.showModal` を未設定にする)か、`close` コールバックを実行させる方法で操作することで閉じることができます。`close` コールバックはプログラムで戻る遷移を実行します。
API
`pushState` の最初の引数は、現在の URL を基準とした相対 URL です。現在の URL のままにするには、`''` を使用します。
2 番目の引数は新しいページ状態であり、page ストア を介して `$page.state` としてアクセスできます。`App.PageState` インターフェース(通常は `src/app.d.ts` 内)を宣言することで、ページ状態をタイプセーフにすることができます。
新しい履歴エントリを作成せずにページ状態を設定するには、`pushState` の代わりに `replaceState` を使用します。
ルートのデータ読み込み
シャロールーティングを行う場合、現在のページ内に別の `+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';
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 が利用できない場合の適切なフォールバック動作を考えてみてください。