核心概念
路由
在 GitHub 上編輯此頁面SvelteKit 的核心是一個基於檔案系統的路由器。應用程式的路由(即使用者可以存取的 URL 路徑)是由程式碼庫中的目錄定義的
src/routes
是根路由src/routes/about
建立一個/about
路由src/routes/blog/[slug]
建立一個具有參數slug
的路由,當使用者要求類似/blog/hello-world
的頁面時,可以使用該參數動態載入資料
你可以透過編輯 專案設定 將
src/routes
變更為不同的目錄。
每個路由目錄包含一個或多個路由檔案,它們可以用其 +
前綴來識別。
+page永久連結
+page.svelte永久連結
+page.svelte
元件定義了應用程式的頁面。預設情況下,頁面會在伺服器上(SSR)渲染以進行初始要求,並在瀏覽器中(CSR)渲染以進行後續導覽。
<h1>Hello and welcome to my site!</h1>
<a href="/about">About my site</a>
<h1>About this site</h1>
<p>TODO...</p>
<a href="/">Home</a>
<script>
/** @type {import('./$types').PageData} */
export let data;
</script>
<h1>{data.title}</h1>
<div>{@html data.content}</div>
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
<h1>{data.title}</h1>
<div>{@html data.content}</div>
請注意,SvelteKit 使用
<a>
元素在路由之間導覽,而不是特定於架構的<Link>
元件。
+page.js永久連結
通常,頁面需要在渲染之前載入一些資料。為此,我們加入一個 +page.js
模組,該模組會匯出一個 load
函式
ts
import {error } from '@sveltejs/kit';/** @type {import('./$types').PageLoad} */export functionload ({params }) {if (params .slug === 'hello-world') {return {title : 'Hello world!',content : 'Welcome to our blog. Lorem ipsum dolor sit amet...'};}error (404, 'Not found');}
ts
import {error } from '@sveltejs/kit';import type {PageLoad } from './$types';export constload :PageLoad = ({params }) => {if (params .slug === 'hello-world') {return {title : 'Hello world!',content : 'Welcome to our blog. Lorem ipsum dolor sit amet...',};}error (404, 'Not found');};
此函式與 +page.svelte
一起執行,這表示它會在伺服器端渲染期間在伺服器上執行,並在客戶端導覽期間在瀏覽器中執行。請參閱 load
以取得 API 的完整詳細資料。
除了 load
之外,+page.js
還可以匯出設定頁面行為的值
export const prerender = true
或false
或'auto'
export const ssr = true
或false
export const csr = true
或false
您可以在 頁面選項 中找到有關這些選項的更多資訊。
+page.server.js永久連結
如果您的 load
函式只能在伺服器上執行,例如,如果它需要從資料庫擷取資料,或者您需要存取私人 環境變數,例如 API 金鑰,則可以將 +page.js
重新命名為 +page.server.js
,並將 PageLoad
類型變更為 PageServerLoad
。
ts
import {error } from '@sveltejs/kit';/** @type {import('./$types').PageServerLoad} */export async functionload ({params }) {constpost = awaitgetPostFromDatabase (params .slug );if (post ) {returnpost ;}error (404, 'Not found');}
ts
import {error } from '@sveltejs/kit';import type {PageServerLoad } from './$types';export constload :PageServerLoad = async ({params }) => {constpost = awaitgetPostFromDatabase (params .slug );if (post ) {returnpost ;}error (404, 'Not found');};
在客戶端導覽期間,SvelteKit 會從伺服器載入這些資料,這表示傳回的值必須使用 devalue 序列化。請參閱 load
以取得 API 的完整詳細資料。
與 +page.js
類似,+page.server.js
可以匯出 頁面選項,例如 prerender
、ssr
和 csr
。
+page.server.js
檔案也可以匯出動作。如果 load
讓您從伺服器讀取資料,actions
讓您可以使用 <form>
元素將資料寫入伺服器。若要了解如何使用它們,請參閱 表單動作 部分。
+error永久連結
如果在 load
期間發生錯誤,SvelteKit 會呈現預設的錯誤頁面。您可以透過新增 +error.svelte
檔案,針對每個路由自訂此錯誤頁面
<script>
import { page } from '$app/stores';
</script>
<h1>{$page.status}: {$page.error.message}</h1>
<script lang="ts">
import { page } from '$app/stores';
</script>
<h1>{$page.status}: {$page.error.message}</h1>
SvelteKit 會「向上尋找」最近的錯誤邊界,如果上述檔案不存在,它會嘗試 src/routes/blog/+error.svelte
,然後嘗試 src/routes/+error.svelte
,最後才會呈現預設的錯誤頁面。如果這樣失敗了(或如果錯誤是由根 +layout
的 load
函式引發,而該函式位於根 +error
的「上方」),SvelteKit 會放棄並呈現靜態後備錯誤頁面,您可以透過建立 src/error.html
檔案自訂此頁面。
如果錯誤發生在 +layout(.server).js
中的 load
函式內,樹狀結構中最近的錯誤邊界會是該佈局上方的 +error.svelte
檔案(而不是其旁邊)。
如果找不到路由(404),將會使用 src/routes/+error.svelte
(或如果該檔案不存在,則使用預設錯誤頁面)。
當錯誤發生在
handle
或 +server.js 要求處理程式內時,不會使用+error.svelte
。
你可以 在此處 閱讀更多關於錯誤處理的資訊。
+layoutpermalink
到目前為止,我們將頁面視為完全獨立的元件,在導覽時,現有的 +page.svelte
元件將會被銷毀,新的元件將取而代之。
但在許多應用程式中,有些元素應該在每個頁面上都可見,例如頂層導覽或頁尾。我們可以將它們放在佈局中,而不是在每個 +page.svelte
中重複它們。
+layout.sveltepermalink
若要建立套用至每個頁面的佈局,請建立一個名為 src/routes/+layout.svelte
的檔案。預設佈局(如果你沒有自訂佈局,SvelteKit 會使用的佈局)如下所示...
<slot></slot>
...但我們可以新增任何想要的標記、樣式和行為。唯一的需求是元件必須包含用於頁面內容的 <slot>
。例如,我們來新增一個導覽列
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/settings">Settings</a>
</nav>
<slot></slot>
如果我們為 /
、/about
和 /settings
建立頁面...
<h1>Home</h1>
<h1>About</h1>
<h1>Settings</h1>
...導覽列將始終可見,而且在三個頁面之間按一下只會導致 <h1>
被取代。
佈局可以巢狀。假設我們不只有一個 /settings
頁面,而是有巢狀頁面,例如 /settings/profile
和 /settings/notifications
,並有一個共用的子選單(實際範例請參閱 github.com/settings)。
我們可以建立一個只套用於 /settings
以下頁面的佈局(同時繼承具有頂層導覽的根佈局)
<script>
/** @type {import('./$types').LayoutData} */
export let data;
</script>
<h1>Settings</h1>
<div class="submenu">
{#each data.sections as section}
<a href="/settings/{section.slug}">{section.title}</a>
{/each}
</div>
<slot></slot>
<script lang="ts">
import type { LayoutData } from './$types';
export let data: LayoutData;
</script>
<h1>Settings</h1>
<div class="submenu">
{#each data.sections as section}
<a href="/settings/{section.slug}">{section.title}</a>
{/each}
</div>
<slot></slot>
你可以查看下一節中 +layout.js
範例中的 data
如何填入資料。
預設情況下,每個佈局都會繼承其上方的佈局。有時候這並非你想要的,這種情況下,進階佈局 可以幫你。
+layout.jspermalink
就像 +page.svelte
從 +page.js
載入資料一樣,你的 +layout.svelte
元件也可以從 +layout.js
中的 load
函式取得資料。
ts
/** @type {import('./$types').LayoutLoad} */export functionload () {return {sections : [{slug : 'profile',title : 'Profile' },{slug : 'notifications',title : 'Notifications' }]};}
ts
import type {LayoutLoad } from './$types';export constload :LayoutLoad = () => {return {sections : [{slug : 'profile',title : 'Profile' },{slug : 'notifications',title : 'Notifications' },],};};
如果 +layout.js
匯出 頁面選項 — prerender
、ssr
和 csr
— 它們將用作子頁面的預設值。
從版面配置的 load
函數傳回的資料也可用於所有其子頁面
<script>
/** @type {import('./$types').PageData} */
export let data;
console.log(data.sections); // [{ slug: 'profile', title: 'Profile' }, ...]
</script>
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
console.log(data.sections); // [{ slug: 'profile', title: 'Profile' }, ...]
</script>
在頁面之間導航時,版面配置資料通常不會改變。SvelteKit 將在必要時智慧地重新執行
load
函數。
+layout.server.js永久連結
若要在伺服器上執行版面配置的 load
函數,請將其移至 +layout.server.js
,並將 LayoutLoad
類型變更為 LayoutServerLoad
。
與 +layout.js
相同,+layout.server.js
可以匯出 頁面選項 — prerender
、ssr
和 csr
。
+server永久連結
除了頁面之外,您還可以定義具有 +server.js
檔案的路由(有時稱為「API 路由」或「端點」),讓您可以完全控制回應。您的 +server.js
檔案會匯出對應於 HTTP 動詞(如 GET
、POST
、PATCH
、PUT
、DELETE
、OPTIONS
和 HEAD
)的函數,這些函數會取得 RequestEvent
參數並傳回 Response
物件。
例如,我們可以建立一個具有 GET
處理常式的 /api/random-number
路由
ts
import {error } from '@sveltejs/kit';/** @type {import('./$types').RequestHandler} */export functionGET ({url }) {constmin =Number (url .searchParams .get ('min') ?? '0');constmax =Number (url .searchParams .get ('max') ?? '1');constd =max -min ;if (isNaN (d ) ||d < 0) {error (400, 'min and max must be numbers, and min must be less than max');}constrandom =min +Math .random () *d ;return newResponse (String (random ));}
ts
import {error } from '@sveltejs/kit';import type {RequestHandler } from './$types';export constGET :RequestHandler = ({url }) => {constmin =Number (url .searchParams .get ('min') ?? '0');constmax =Number (url .searchParams .get ('max') ?? '1');constd =max -min ;if (isNaN (d ) ||d < 0) {error (400, 'min and max must be numbers, and min must be less than max');}constrandom =min +Math .random () *d ;return newResponse (String (random ));};
傳遞給 Response
的第一個參數可以是 ReadableStream
,這使得串流大量資料或建立伺服器傳送事件成為可能(除非部署到會緩衝回應的平台,例如 AWS Lambda)。
您可以使用 @sveltejs/kit
中的 error
、redirect
和 json
方法以方便使用(但您不必這麼做)。
如果拋出錯誤(error(...)
或意外錯誤),回應將會是錯誤的 JSON 表示或備用錯誤頁面,這可透過 src/error.html
來自訂,這取決於 Accept
標頭。
元件在這種情況下不會被渲染。你可以在此處閱讀更多有關錯誤處理的資訊。+error.svelte
在建立
OPTIONS
處理常式時,請注意 Vite 會注入Access-Control-Allow-Origin
和Access-Control-Allow-Methods
標頭,除非你將它們加入,否則這些標頭在製作環境中不會存在。
接收資料永久連結
透過匯出 POST
/PUT
/PATCH
/DELETE
/OPTIONS
/HEAD
處理常式,+server.js
檔案可以用來建立完整的 API
<script>
let a = 0;
let b = 0;
let total = 0;
async function add() {
const response = await fetch('/api/add', {
method: 'POST',
body: JSON.stringify({ a, b }),
headers: {
'content-type': 'application/json'
}
});
total = await response.json();
}
</script>
<input type="number" bind:value={a}> +
<input type="number" bind:value={b}> =
{total}
<button on:click={add}>Calculate</button>
<script lang="ts">
let a = 0;
let b = 0;
let total = 0;
async function add() {
const response = await fetch('/api/add', {
method: 'POST',
body: JSON.stringify({ a, b }),
headers: {
'content-type': 'application/json',
},
});
total = await response.json();
}
</script>
<input type="number" bind:value={a}> +
<input type="number" bind:value={b}> =
{total}
<button on:click={add}>Calculate</button>
ts
import {json } from '@sveltejs/kit';/** @type {import('./$types').RequestHandler} */export async functionPOST ({request }) {const {a ,b } = awaitrequest .json ();returnjson (a +b );}
ts
import {json } from '@sveltejs/kit';import type {RequestHandler } from './$types';export constPOST :RequestHandler = async ({request }) => {const {a ,b } = awaitrequest .json ();returnjson (a +b );};
一般來說,表單動作是從瀏覽器提交資料到伺服器更好的方式。
如果匯出
GET
處理常式,HEAD
要求會傳回GET
處理常式回應主體的content-length
。
備用方法處理常式永久連結
匯出 fallback
處理常式會比對任何未處理的要求方法,包括沒有從 +server.js
專門匯出的方法,例如 MOVE
。
ts
import {json ,text } from '@sveltejs/kit';export async functionPOST ({request }) {const {a ,b } = awaitrequest .json ();returnjson (a +b );}// This handler will respond to PUT, PATCH, DELETE, etc./** @type {import('./$types').RequestHandler} */export async functionfallback ({request }) {returntext (`I caught your ${request .method } request!`);}
ts
import {json ,text } from '@sveltejs/kit';import type {RequestHandler } from './$types';export async functionPOST ({request }) {const {a ,b } = awaitrequest .json ();returnjson (a +b );}// This handler will respond to PUT, PATCH, DELETE, etc.export constfallback :RequestHandler = async ({request }) => {returntext (`I caught your ${request .method } request!`);};
對於
HEAD
要求,GET
處理常式優先於fallback
處理常式。
內容協商永久連結
+server.js
檔案可以放置在與 +page
檔案相同的目錄中,讓同一路由可以是頁面或 API 端點。為了判斷,SvelteKit 會套用下列規則
PUT
/PATCH
/DELETE
/OPTIONS
要求總是會由+server.js
處理,因為它們不適用於頁面GET
/POST
/HEAD
要求會被視為頁面要求,如果accept
標頭優先考慮text/html
(換句話說,這是瀏覽器頁面要求),否則它們會由+server.js
處理。- 對
GET
要求的回應會包含Vary: Accept
標頭,這樣代理伺服器和瀏覽器才能分別快取 HTML 和 JSON 回應。
$types永久連結
在以上範例中,我們一直從 $types.d.ts
檔案匯入類型。這是 SvelteKit 在隱藏目錄中為你建立的檔案,如果你使用 TypeScript(或具有 JSDoc 類型註解的 JavaScript)來提供類型安全性,以便使用你的根檔案時。
例如,使用 PageData
(或 LayoutData
,對於 +layout.svelte
檔案)註解 export let data
會告訴 TypeScript,data
的類型是從 load
傳回的任何內容
<script>
/** @type {import('./$types').PageData} */
export let data;
</script>
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
反過來,使用 PageLoad
、PageServerLoad
、LayoutLoad
或 LayoutServerLoad
(分別用於 +page.js
、+page.server.js
、+layout.js
和 +layout.server.js
)註解 load
函數可確保 params
和回傳值類型正確。
如果你使用 VS Code 或任何支援語言伺服器協定和 TypeScript 外掛程式的 IDE,那麼你可以完全省略這些類型!Svelte 的 IDE 工具會為你插入正確的類型,因此你可以在不自己撰寫的情況下進行類型檢查。它也與我們的命令列工具 svelte-check
搭配使用。
你可以在我們的部落格文章中進一步了解省略 $types
。
其他檔案永久連結
SvelteKit 會忽略路由目錄中的任何其他檔案。這表示你可以將元件和實用程式模組與需要它們的路由並置。
如果元件和模組需要由多個路由使用,建議將它們放在 $lib
中。