Svelte / SvelteKit 基础知识参考字典

要点

本篇是 Svelte 5 与 SvelteKit 2 的条目式速查,按用途分六组:响应式符文、模板语法、组件与生命周期、SvelteKit 路由文件、SvelteKit 模块、配置与工程;文末有全量速查表,可只搜表定位条目。版本基线为 Svelte 5.43.x 与 SvelteKit 2.48.x(截至 2025-11-03 的稳定线),仅在此基线成立的特性单独标注版本。路由与 load 的完整讲解不在本篇重复,见SvelteKit 路由与数据加载:load 函数详解;框架定位与选型判断见开山篇Svelte 入门。

响应式符文组

符文(runes)是编译期标记而非运行时函数,写给编译器看。全量如下:

符文 一句话用途 有什么坑
$state(v) 声明响应式状态 对象与数组是深层代理,直接 console.log 全是 Proxy;要看原始值用 $state.snapshot
$derived(expr) 派生值,依赖变化自动重算 派生值只读,在别处赋值是编译错误;多行逻辑用 $derived.by(() => {…})
$effect(fn) 副作用,依赖的信号变化时重跑 返回的函数作清理;不要在里面写能算出来的状态,那该用 $derived
$effect.pre(fn) DOM 更新前执行的副作用 测量布局(读滚动位置等)用它,$effect 里读是更新后的旧值
$props() 解构声明组件入参 带默认值写 let { size = 24 } = $props();剩余属性用 rest 解构
$bindable(v) 标记允许双向绑定的入参 只包 $props 里解构出的属性;未标记的 prop 上 bind: 是编译错误
$inspect(v) 开发期打印值变化 生产构建中被剔除,别拿它当日志系统
$host() 自定义元素内部取宿主 仅 custom elements 场景

$state:响应式从声明开始

let count = $state(0);
let list = $state(['a', 'b']);
list.push('c');                    // 数组方法直接用,深层代理会自动触发更新
console.log($state.snapshot(list)); // ['a', 'b', 'c'] —— 排查时的原始值

一句话语义:声明”这个值变了,用它的地方要更新”。类字段同样可写 count = $state(0)。

⚠️ 常见坑:从 Svelte 4 教程带过来的习惯——解构 props 或重组件入参后丢失响应性。let { items } = $props() 拿到的 items 若被子组件用 $state 重建,父层引用不会跟着换;要保持追踪,解构后直接用,别再赋值给普通变量。

$derived:能算出来的不要存

let query = $state('');
let hits = $derived.by(() => {
  const q = query.trim().toLowerCase();
  return q ? all.filter(x => x.title.toLowerCase().includes(q)) : all;
});

一句话语义:声明”这个值由别的值算出”,无需手写依赖列表。

⚠️ 常见坑:把派生写成 $effect 加赋值——多一轮更新循环,依赖关系被藏进副作用,是官方文档点名的头号误用;判断标准就一条:能从别的值算出来,就用 $derived。

$effect:只留给”外部世界”

$effect(() => {
  document.title = `购物车 ${items.length} 件`;  // 触碰 Svelte 管辖之外的 DOM
  return () => console.log('清理');              // 可选清理函数
});

⚠️ 常见坑:在 $effect 里发请求”补数据”来替代 load——SSR 首屏没有这份请求,白做一次服务端渲染;数据该走 SvelteKit 的 load(见路由篇),$effect 留给打点、标题、非 Svelte 组件的桥接。

模板语法组

语法 一句话用途 有什么坑
{#if} / {:else if} / {:else} / {/if} 条件渲染 无三元之外的表达式限制,常规 JS 表达式均可
{#each list as item (item.id)} 列表渲染,括号里是 key 不写 key 是”就地复用”,列表重排时输入框状态会串行;能定唯一 id 就写 key
{#await p} {:then v} {:catch e} Promise 三态渲染 服务端 load 返回的流式 Promise 用它接,见路由篇
{#key expr} 表达式变化时销毁重建内部块 重置组件状态的手段,滥用会丢性能与状态
{#snippet name(a)} / {@render name(a)} 定义与渲染可复用模板块(替代旧 slot) 声明即值,可作为 props 传给子组件;旧 slot 语法仍兼容但已让位
{@html str} 插入原始 HTML 不消毒,内容含用户输入就是存储型 XSS;必须先白名单消毒
{onclick={() => …}} 事件属性(Svelte 5 写法) 旧 on:click 指令已弃用;修饰符 |preventDefault 一并取消,需手动 e.preventDefault()
bind:value / bind:group / bind:this 双向绑定与元素引用 bind:this 绑的是元素实例,在挂载前读是 undefined
class:active={cond} 条件 class 指令 5.16 起 class 属性直接支持对象/数组写法,批量场景更清爽
use:action 元素级扩展(action) 返回 { update, destroy };参数变化走 update,不是重建节点
transition:fade / in: / out: 进出场过渡 本地过渡默认不随全局状态播放,需 |global 修饰才跨块生效
animate:flip keyed each 重排动画 只对带 key 的 each 直接子元素生效,套一层 div 就失灵
错误边界(5.3+) failed snippet 兜底 UI,onerror 收错误对象;SSR 期间不捕获
{@attach fn} attachments(5.29+) 比 action 更贴近元素生命周期;新代码二选一即可,不必迁移存量 action

⚠️ 常见坑(本组最贵的一个):{@html} 直出用户输入。哪怕内容来自”自家编辑器”,也要在服务端用白名单消毒后再入库或直出——Svelte 不替你消毒,这行语法是全 Svelte 应用里最常见的 XSS 入口。

组件与生命周期组

API 一句话用途 有什么坑
mount(App, { target, props }) 客户端挂载组件(Svelte 5 入口) 替代 new Component();返回实例传给 unmount
hydrate(App, { target }) 在 SSR 产物上激活 与服务端渲染结果不一致会告警并整块重渲
unmount(app) 卸载组件并跑清理 Svelte 5 返回 Promise 形态的清理句柄
tick() 等本轮 DOM 更新落定 改完状态立刻量 DOM 要先 await tick()
flushSync(fn) 强制同步刷新更新 与第三方库桥接时用,普通业务代码不需要
untrack(fn) 读信号但不建立依赖 在 $effect 里读”只想要当前值”的大对象时用它防误触发
createEventDispatcher (已弃用)组件事件 Svelte 5 用回调 props(onXxx)替代,新代码不要再写

SvelteKit 路由文件组

文件树即路由表,各特殊文件的分工速查如下(优先级、动态段写法与 load 重跑规则的完整版见路由篇):

文件 一句话用途 有什么坑
+page.svelte 页面 UI 数据从 let { data } = $props() 进来
+page.js universal load 跑在客户端,密钥和私密导入进来就泄漏
+page.server.js server load 与 actions 仅服务端;返回值必须可序列化(devalue)
+layout.svelte 嵌套布局,{@render children()} 布局实例跨子路由导航保留,状态不会自动重置
+layout.js / .server.js 子树共享数据 / 页面选项(prerender、ssr、csr) 写在 layout 上对整棵子树生效
+server.js API 端点(GET/POST…) 返回 Response 对象;与 +page.svelte 同目录时按 Accept 分流
+error.svelte 层级错误兜底 就近接管;根部那个兜住全部
hooks.server.js handle:每个请求的入口拦截 必须调 resolve(event) 返回响应,忘了整站无响应

SvelteKit 模块组

模块 / 导出 一句话用途 有什么坑
$app/state: page 当前页的 url/params/data/status/form/error(2.12+) 是响应式对象不是 store:读 page.data,不写 $page.data
$app/state: navigating / updated 导航进行中信息 / 部署更新检测 $app/stores 是它的前身,已弃用但仍可用
$app/navigation: goto 编程式导航 默认不强制刷新数据,同 URL 用 invalidate
$app/navigation: invalidate / invalidateAll 手动触发 load 重跑 只对”读过该依赖”的 load 生效,见路由篇
$app/navigation: prefetch / preloadData 悬停预取 / 提前跑 load data-sveltekit-preloaddata 属性可声明式开启
$app/forms: enhance use:enhance 渐进增强表单 自定义回调时记得调默认行为 update(),否则 action 结果不回填
$app/forms: applyAction / deserialize 手动消费 action 结果 自造提交逻辑时用,别自己 fetch action URL
$app/paths: base / assets 部署路径前缀 手拼 URL 忘加 base,非根路径部署时资源全 404
$app/environment: browser / dev / building 运行环境判断 替代”typeof window !== ‘undefined'”式判断
$env/static/private 构建期内联的私密变量 只能进 server load/actions/hooks;被 universal load 或组件 import 直接报错
$env/static/public 构建期内联的公开变量 会打进客户端产物,放敏感值就等于公开
$env/dynamic/private|public 运行时读取的环境变量 private 版只能在服务端用;值不内联,改环境不用重建
@sveltejs/kit: error(status, msg) 抛出带状态的请求错误 SvelteKit 2 改为抛出式;用 throw 或直接调用皆可
@sveltejs/kit: redirect(status, url) 抛出重定向 不能放在 try 块里——catch 会把它吞掉
@sveltejs/kit: fail(status, data) action 返回校验错误 4xx 校验错误用 fail 而不是 error:前者回填表单,后者进错误页
@sveltejs/kit: json / text 构造 Response 的便捷函数 +server.js 里返回 Response 也可以,函数只是省事

hooks 的两个文件级导出单独说一句:handle 是每个请求的必经之路(挂 event.locals、鉴权、日志都在这),多个中间件用 sequence()(来自 @sveltejs/kit/hooks)串联;handleError 只处理未捕获异常,不能用它改变响应内容。

配置与工程组

条目 一句话用途 有什么坑
npx sv create [path] 官方脚手架(sv CLI,本文时点 0.9.x) –template minimal/demo/library/addon、–types ts/jsdoc、–no-add-ons、–install npm/pnpm/yarn/bun/deno
sv add 给项目加生态件(eslint、prettier、tailwindcss、vitest、playwright 等) 清单随版本变,以 sv add –help 为准
sv check 类型与模板检查(svelte-check 封装) 放 CI 跑,别靠编辑器插件兜底
sv migrate 官方迁移脚本(如 Svelte 4 组件迁移到 5) 机械转换覆盖不到全部,跑完必须人工过一遍
svelte.config.js: kit.adapter 部署目标适配器 adapter-auto 在未知平台回落 node 可跑但告警,自建服务器显式用 adapter-node
adapter-static 纯静态导出 全站必须可 prerender,用了一个 server load 就打不出包
kit.csrf.origin 检查 POST 按请求头 Origin 校验 curl 直接 POST action 会被 403,测试要带 Origin 头
compilerOptions.experimental.async 实验性 async SSR(Svelte 5.39.3+ / Kit 2.43+) 截至本文仍是实验特性,生产以官方文档为准

全量速查表

条目 一句话用途 有什么坑
$state 响应式状态 深层代理,看原始值用 snapshot
$derived / $derived.by 派生值 能算出来的别用 effect 存
$effect / $effect.pre 副作用 / DOM 更新前 只留给外部世界;量布局用 pre
$props / $bindable 入参 / 可双向入参 未标记的 prop 不能 bind:
{#each (key)} 带 key 列表渲染 重排列表必须写 key
{@html} 原始 HTML 不消毒就是 XSS
onclick 事件属性 Svelte 5 事件写法 on: 指令与修饰符已弃用
bind:value / bind:this 双向绑定 / 引用 bind:this 挂载前是 undefined
use:action / {@attach} 元素扩展(action / 5.29+ attachment) 参数变化走 update 不重建
错误边界(5.3+) SSR 期间不捕获
mount / hydrate / unmount 组件挂载三件套 替代 new Component()
+page.js vs +page.server.js universal vs server load universal 里别碰密钥
event.fetch load 内请求 全局 fetch 丢凭证、无相对路径
invalidate / invalidateAll 手动重跑 load server load 不随查询串重跑
$app/state: page 页面状态(2.12+) 响应式对象,非 store
goto / prefetch 导航与预取 同 URL 要数据刷新用 invalidate
use:enhance 表单渐进增强 自定义回调别丢了默认 update()
$env/static/* 构建期内联环境变量 private 进不了客户端,public 全公开
error / redirect / fail 错误 / 重定向 / action 校验失败 redirect 别放 try 里;校验错误用 fail
adapter-node / adapter-static 自托管 / 纯静态 static 要求全站可 prerender

延伸阅读

路由与 load 的机制讲解见SvelteKit 路由与数据加载;把这些 API 组合起来做一个完整应用的过程见实战篇用 SvelteKit 做一个 Markdown 片段收藏夹(2025-11-06 发布);按阶段串起本站相关文章的路径见Svelte 学习路线(2025-11-13 发布);模块与 ESM 基础不熟的,先补站内Node.js 模块与 ESM。

版本核实(以官方文档为准):截至本文(2025-11-03)稳定线为 Svelte 5.43.x、SvelteKit 2.48.x;$app/state 自 SvelteKit 2.12(2024-12)提供并取代 $app/stores;svelte:boundary 自 Svelte 5.3(2024-12);class 属性对象/数组写法自 5.16(2024-12);attachments 自 5.29(2025-05);remote functions 自 SvelteKit 2.27(2025-07)起为实验特性;实验性 async SSR 需 Svelte 5.39.3+ 与 SvelteKit 2.43+。安装命令不钉版本号,API 细节以 svelte.dev 当前文档为准。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇