路由基础
本教程共 50 篇 · 第 44 篇 · 更新于 2026-08-05 · 约 7 分钟阅读
本节目标:掌握 SvelteKit 的文件路由系统,学会创建页面、动态路由、布局组件和 API 端点,了解路由跳转和链接预加载。
文件路由系统
SvelteKit 用文件目录来定义路由。src/routes 里的每个目录对应一个 URL 路径:
src/routes/→/src/routes/about/→/aboutsrc/routes/blog/[slug]/→/blog/hello-world(动态参数)
每个路由目录里放以 + 开头的文件,SvelteKit 根据文件名识别用途。
+page.svelte:定义页面
+page.svelte 是页面组件文件。最简单的页面:
<!-- src/routes/+page.svelte -->
<h1>欢迎来到我的网站</h1>
<a href="/about">关于我们</a>
<!-- src/routes/about/+page.svelte -->
<h1>关于本站</h1>
<a href="/">返回首页</a>
NoteSvelteKit 用标准的
<a>标签做导航,不需要专门的<Link>组件。点击<a>时,SvelteKit 拦截默认跳转,改为客户端路由。
+page.js 和 +page.server.js:加载数据
页面需要数据时,加一个 +page.js 文件,导出 load 函数:
// src/routes/blog/[slug]/+page.js
import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
if (params.slug === 'hello-world') {
return {
title: 'Hello world!',
content: '欢迎来到博客...'
};
}
error(404, '文章不存在');
}
页面组件通过 data prop 接收数据:
<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<h1>{data.title}</h1>
<div>{data.content}</div>
+page.js 和 +page.server.js 的区别:
| 文件 | 运行环境 | 适用场景 |
|---|---|---|
+page.js | 服务端 + 客户端 | 通用数据加载,可在导航时浏览器端运行 |
+page.server.js | 仅服务端 | 访问数据库、使用私密环境变量 |
Tip需要访问数据库或 API 密钥时用
+page.server.js。数据可以在浏览器端用公开 API 获取时用+page.js。
动态路由
用方括号创建动态参数:
src/routes/blog/[slug]/+page.svelte → /blog/hello-world
src/routes/blog/[slug]/+page.svelte → /blog/svelte-5-guide
slug 参数在 load 函数和页面组件中都能访问:
<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
/** @type {import('./$types').PageProps} */
let { data, params } = $props();
</script>
<h1>{data.title}</h1>
<p>当前 slug: {params.slug}</p>
+layout.svelte:共享布局
多个页面共享导航栏、侧边栏等元素时,用布局组件。在 src/routes/+layout.svelte 定义根布局:
<!-- src/routes/+layout.svelte -->
<script>
let { children } = $props();
</script>
<nav>
<a href="/">首页</a>
<a href="/about">关于</a>
<a href="/settings">设置</a>
</nav>
<main>
{@render children()}
</main>
{@render children()} 渲染当前页面内容。布局组件在页面切换时不会重新创建,只有 children 部分更新。
布局可以嵌套。/settings 下的子页面可以有自己的布局:
<!-- src/routes/settings/+layout.svelte -->
<script>
/** @type {import('./$types').LayoutProps} */
let { data, children } = $props();
</script>
<h1>设置</h1>
<div class="submenu">
{#each data.sections as section}
<a href="/settings/{section.slug}">{section.title}</a>
{/each}
</div>
{@render children()}
+layout.js 和 +layout.server.js
布局也可以有 load 函数,数据会传给所有子页面:
// src/routes/settings/+layout.js
/** @type {import('./$types').LayoutLoad} */
export function load() {
return {
sections: [
{ slug: 'profile', title: '个人资料' },
{ slug: 'notifications', title: '通知' }
]
};
}
子页面能直接访问布局数据:
<!-- src/routes/settings/profile/+page.svelte -->
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<!-- data 包含布局的 load 数据和页面的 load 数据 -->
<p>{data.sections[0].title}</p>
+error.svelte:错误页面
load 函数抛出错误时,SvelteKit 渲染 +error.svelte:
<!-- src/routes/blog/[slug]/+error.svelte -->
<script>
import { page } from '$app/state';
</script>
<h1>{page.status}: {page.error.message}</h1>
$app/state 提供 page 对象,包含 status、error、url 等信息。
NoteSvelteKit 2.12 起用
$app/state替代旧的$app/stores。如果你用的是更早版本,用$app/stores中的pagestore。
错误页面会向上查找——如果 /blog/[slug]/ 下没有 +error.svelte,就去 /blog/ 找,再找不到去 / 找。
+server.js:API 路由
+server.js 文件创建 API 端点,导出对应 HTTP 方法的函数:
// src/routes/api/random-number/+server.js
/** @type {import('./$types').RequestHandler} */
export function GET({ url }) {
const min = Number(url.searchParams.get('min') ?? '0');
const max = Number(url.searchParams.get('max') ?? '1');
const random = min + Math.random() * (max - min);
return new Response(String(random));
}
支持 GET、POST、PATCH、PUT、DELETE 等方法。用 @sveltejs/kit 的辅助函数简化响应:
import { json, error } from '@sveltejs/kit';
export async function POST({ request }) {
const { a, b } = await request.json();
return json(a + b);
}
路由跳转:goto()
除了用 <a> 标签,还可以编程式跳转:
<script>
import { goto } from '$app/navigation';
let searchQuery = $state('');
function handleSearch() {
goto(`/search?q=${searchQuery}`);
}
</script>
<input bind:value={searchQuery} />
<button onclick={handleSearch}>搜索</button>
goto 的选项:
goto('/about', {
replaceState: true, // 替换历史记录而不是新增
noScroll: true, // 不滚动到页面顶部
keepFocus: true // 保持当前焦点元素
});
Tip外部 URL 跳转用
window.location = url,不要用goto()。goto只处理应用内部路由。
链接预加载
SvelteKit 会在用户 hover 链接时预加载页面代码和数据,让点击后的跳转几乎零延迟。
默认模板在 app.html 的 <body> 上设置了全局预加载:
<body data-sveltekit-preload-data="hover">
两个选项:
| 值 | 行为 |
|---|---|
hover | 鼠标悬停时预加载数据和代码(默认) |
tap | 点击时才开始预加载 |
单个链接可以覆盖全局设置:
<a href="/realtime" data-sveltekit-preload-data="tap">
实时数据(不预加载)
</a>
还可以只预加载代码不预加载数据:
<a href="/blog/post" data-sveltekit-preload-code="viewport">
进入视口就预加载代码
</a>
Note用户开启了省流量模式(
navigator.connection.saveData)时,预加载会自动禁用。
其他链接属性
| 属性 | 作用 |
|---|---|
data-sveltekit-reload | 点击时整页刷新,不用客户端路由 |
data-sveltekit-replacestate | 替换历史记录而非新增 |
data-sveltekit-noscroll | 跳转后不滚动到顶部 |
<a href="/external-page" data-sveltekit-reload>外部页面</a>
<a href="/tab2" data-sveltekit-replacestate>标签页切换</a>
路由文件速查表
| 文件 | 作用 | 运行环境 |
|---|---|---|
+page.svelte | 页面组件 | 服务端 + 客户端 |
+page.js | 页面数据加载(通用) | 服务端 + 客户端 |
+page.server.js | 页面数据加载(服务端) | 仅服务端 |
+layout.svelte | 布局组件 | 服务端 + 客户端 |
+layout.js | 布局数据加载(通用) | 服务端 + 客户端 |
+layout.server.js | 布局数据加载(服务端) | 仅服务端 |
+error.svelte | 错误页面 | 服务端 + 客户端 |
+server.js | API 端点 | 仅服务端 |
本节回顾
- SvelteKit 用文件目录定义路由,
src/routes/about/对应/about +page.svelte定义页面,+page.js/+page.server.js加载数据[slug]方括号创建动态路由参数+layout.svelte定义共享布局,用{@render children()}渲染页面内容- 布局可嵌套,布局的
load数据会传给所有子页面 +error.svelte处理错误页面,向上查找最近的错误边界+server.js创建 API 端点,导出GET/POST等方法goto()编程式跳转,data-sveltekit-preload-data控制预加载行为