進階
進階路由
在 GitHub 上編輯此頁面Rest 參數永久連結
如果路由區段數目未知,您可以使用 rest 語法 — 例如,您可以這樣實作 GitHub 的檔案檢視器...
/[org]/[repo]/tree/[branch]/[...file]
...在這種情況下,對 /sveltejs/kit/tree/main/documentation/docs/04-advanced-routing.md
的請求將導致以下參數可供頁面使用
ts
{org: 'sveltejs',repo : 'kit',branch : 'main',file : 'documentation/docs/04-advanced-routing.md'}
src/routes/a/[...rest]/z/+page.svelte
將匹配/a/z
(即完全沒有參數)以及/a/b/z
和/a/b/c/z
等。請務必檢查 rest 參數的值是否有效,例如使用 比對器。
404 頁面永久連結
Rest 參數也允許您呈現自訂 404。給定這些路由...
src/routes/
├ marx-brothers/
│ ├ chico/
│ ├ harpo/
│ ├ groucho/
│ └ +error.svelte
└ +error.svelte
...如果您訪問 /marx-brothers/karl
,則不會呈現 marx-brothers/+error.svelte
檔案,因為沒有匹配的路由。如果您想呈現巢狀錯誤頁面,您應該建立一個與任何 /marx-brothers/*
請求相符的路由,並從中傳回 404
src/routes/
├ marx-brothers/
| ├ [...path]/
│ ├ chico/
│ ├ harpo/
│ ├ groucho/
│ └ +error.svelte
└ +error.svelte
ts
import {error } from '@sveltejs/kit';/** @type {import('./$types').PageLoad} */export functionload (event ) {error (404, 'Not Found');}
ts
import {error } from '@sveltejs/kit';import type {PageLoad } from './$types';export constload :PageLoad = (event ) => {error (404, 'Not Found');};
如果您不處理 404 案例,它們將出現在
handleError
選用參數永久連結
像 [lang]/home
的路由包含一個名為 lang
的必要參數。有時讓這些參數成為選用參數是有益的,因此在這個範例中 home
和 en/home
都指向同一個頁面。您可以透過在另一個方括號對中包裝參數來做到這一點:[[lang]]/home
請注意,選用路由參數不能出現在 rest 參數 ([...rest]/[[optional]]
) 之後,因為參數是「貪婪地」匹配,而且選用參數永遠不會被使用。
匹配永久連結
像 src/routes/archive/[page]
的路由會匹配 /archive/3
,但也會匹配 /archive/potato
。我們不想要這樣。您可以透過新增一個「比對器」來確保路由參數格式正確,這個比對器會取得參數字串 ("3"
或 "potato"
) 並傳回 true
(如果有效) 到您的 params
目錄...
ts
/** @type {import('@sveltejs/kit').ParamMatcher} */export functionmatch (param ) {return /^\d+$/.test (param );}
ts
import type {ParamMatcher } from '@sveltejs/kit';export constmatch :ParamMatcher = (param ) => {return /^\d+$/.test (param );};
...並擴充您的路由
src/routes/archive/[page]
src/routes/archive/[page=integer]
如果路徑名稱不匹配,SvelteKit 會嘗試匹配其他路由 (使用下方指定的排序順序),最後才會傳回 404。
params
目錄中的每個模組都對應到一個比對器,但 *.test.js
和 *.spec.js
檔案除外,這些檔案可以用於單元測試您的比對器。
比對器會在伺服器和瀏覽器上執行。
排序永久連結
有多個路由可能匹配給定的路徑。例如,以下每個路由都會匹配 /foo-abc
src/routes/[...catchall]/+page.svelte
src/routes/[[a=x]]/+page.svelte
src/routes/[b]/+page.svelte
src/routes/foo-[c]/+page.svelte
src/routes/foo-abc/+page.svelte
SvelteKit 需要知道正在要求哪個路由。為此,它會根據下列規則對它們進行排序...
- 較具體的路由優先順序較高 (例如,沒有參數的路由比具有動態參數的路由更具體,依此類推)
- 具有 比對器 (
[name=type]
) 的參數優先順序高於沒有比對器的參數 ([name]
) [[optional]]
和[...rest]
參數會被忽略,除非它們是路由的最後一部分,這種情況下它們會被視為優先順序最低。換句話說,x/[[y]]/z
在排序時會被視為等同於x/z
- 平手會按字母順序解決
... 導致此排序,意即 /foo-abc
會呼叫 src/routes/foo-abc/+page.svelte
,而 /foo-def
會呼叫 src/routes/foo-[c]/+page.svelte
,而非較不具體的路由
src/routes/foo-abc/+page.svelte
src/routes/foo-[c]/+page.svelte
src/routes/[[a=x]]/+page.svelte
src/routes/[b]/+page.svelte
src/routes/[...catchall]/+page.svelte
編碼永久連結
有些字元無法用於檔案系統中,例如 Linux 和 Mac 上的 /
,Windows 上的 \ / : * ? " < > |
。#
和 %
字元在 URL 中有特殊意義,而 [ ] ( )
字元對 SvelteKit 來說有特殊意義,因此這些字元也不能直接用於路由中。
若要在路由中使用這些字元,可以使用十六進位跳脫序列,其格式為 [x+nn]
,其中 nn
是十六進位字元碼
\
—[x+5c]
/
—[x+2f]
:
—[x+3a]
*
—[x+2a]
?
—[x+3f]
"
—[x+22]
<
—[x+3c]
>
—[x+3e]
|
—[x+7c]
#
—[x+23]
%
—[x+25]
[
—[x+5b]
]
—[x+5d]
(
—[x+28]
)
—[x+29]
例如,若要建立一個 /smileys/:-)
路由,你可以建立一個 src/routes/smileys/[x+3a]-[x+29]/+page.svelte
檔案。
你可以使用 JavaScript 來判斷字元的十六進位碼
ts
':'.charCodeAt (0).toString (16); // '3a', hence '[x+3a]'
你也可以使用 Unicode 跳脫序列。一般來說你不需要這麼做,因為你可以直接使用未編碼的字元,但如果你因為某些原因無法在檔案名稱中使用表情符號,你可以使用跳脫字元。換句話說,這些是等價的
src/routes/[u+d83e][u+dd2a]/+page.svelte
src/routes/🤪/+page.svelte
Unicode 跳脫序列的格式為 [u+nnnn]
,其中 nnnn
是 0000
到 10ffff
之間的有效值。(與 JavaScript 字串跳脫不同,不需要使用代理對來表示 ffff
以上的碼點。)若要深入了解 Unicode 編碼,請參閱 使用 Unicode 進行程式設計。
由於 TypeScript 處理字首為
.
字元的目錄時會遇到困難,因此您可能會發現將這些字元編碼為 e.g..well-known
路徑時會很有用:src/routes/[x+2e]well-known/...
進階版面配置永久連結
預設情況下,版面配置階層會反映路徑階層。在某些情況下,這可能不是您想要的。
(群組)永久連結
也許您有一些「應用程式」路徑,應該使用一種版面配置(例如 /dashboard
或 /item
),而其他「行銷」路徑則應該使用另一種版面配置(/about
或 /testimonials
)。我們可以使用目錄將這些路徑分組,目錄名稱用括號括起來 — 與一般目錄不同,(app)
和 (marketing)
不會影響其內部路徑的 URL 路徑名稱
src/routes/
│ (app)/
│ ├ dashboard/
│ ├ item/
│ └ +layout.svelte
│ (marketing)/
│ ├ about/
│ ├ testimonials/
│ └ +layout.svelte
├ admin/
└ +layout.svelte
您也可以將 +page
直接放在 (group)
內,例如如果 /
應該是 (app)
或 (marketing)
頁面。
跳出版面配置永久連結
根版面配置套用於應用程式的每個頁面 — 如果省略,預設為 <slot />
。如果您希望某些頁面具有與其他頁面不同的版面配置階層,則可以將整個應用程式放在一個或多個群組中,除了不應該繼承共用版面配置的路徑。
在上面的範例中,/admin
路徑不會繼承 (app)
或 (marketing)
版面配置。
+page@永久連結
頁面可以逐個路徑跳出目前的版面配置階層。假設我們在前面範例的 (app)
群組內有一個 /item/[id]/embed
路徑
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page.svelte
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte
通常,這會繼承根版面配置、(app)
版面配置、item
版面配置和 [id]
版面配置。我們可以透過附加 @
後面接區段名稱來重設為其中一個版面配置 — 或對於根版面配置,則為空字串。在此範例中,我們可以從下列選項中選擇
+page@[id].svelte
- 繼承自src/routes/(app)/item/[id]/+layout.svelte
+page@item.svelte
- 繼承自src/routes/(app)/item/+layout.svelte
+page@(app).svelte
- 繼承自src/routes/(app)/+layout.svelte
+page@.svelte
- 繼承自src/routes/+layout.svelte
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page@(app).svelte
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte
+layout@永久連結
如同頁面,佈局也可以使用相同的技術,本身跳脫其父層佈局階層。例如,+layout@.svelte
元件會重設其所有子層路由的階層。
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page.svelte // uses (app)/item/[id]/+layout.svelte
│ │ │ ├ +layout.svelte // inherits from (app)/item/+layout@.svelte
│ │ │ └ +page.svelte // uses (app)/item/+layout@.svelte
│ │ └ +layout@.svelte // inherits from root layout, skipping (app)/+layout.svelte
│ └ +layout.svelte
└ +layout.svelte
何時使用佈局群組永久連結
並非所有使用案例都適合佈局群組,也不應該覺得非用不可。你的使用案例可能會導致複雜的 (group)
巢狀結構,或者你不想為單一例外情況引入 (group)
。使用其他方式,例如組合(可重複使用的 load
函式或 Svelte 元件)或 if 陳述式來達成你的目標,是完全沒問題的。以下範例顯示一個佈局,它會倒轉回根佈局,並重複使用其他佈局也可以使用的元件和函式
<script>
import ReusableLayout from '$lib/ReusableLayout.svelte';
export let data;
</script>
<ReusableLayout {data}>
<slot />
</ReusableLayout>
<script lang="ts">
import ReusableLayout from '$lib/ReusableLayout.svelte';
export let data;
</script>
<ReusableLayout {data}>
<slot />
</ReusableLayout>
ts
import {reusableLoad } from '$lib/reusable-load-function';/** @type {import('./$types').PageLoad} */export functionload (event ) {// Add additional logic here, if neededreturnreusableLoad (event );}
ts
import {reusableLoad } from '$lib/reusable-load-function';import type {PageLoad } from './$types';export constload :PageLoad = (event ) => {// Add additional logic here, if neededreturnreusableLoad (event );};