This is the abridged developer documentation for Svelte and SvelteKit. # Start of Svelte documentation # Overview Svelte 是一个用于在网络上构建用户界面的框架。它使用编译器将用 HTML、CSS 和 JavaScript 编写的声明式组件转换为... ```svelte ``` ...轉換為精簡、高度優化的 JavaScript。 您可以使用它来构建网页上的任何内容,从独立的组件到雄心勃勃的全栈应用程序(使用 Svelte 的配套应用程序框架[SvelteKit](../kit)),以及介于两者之间的所有内容。 这些页面作为参考文档。如果您是 Svelte 的新手,我们建议从[交互式教程](/tutorial)开始,当您有疑问时再回到这里。 您也可以在[沙盒](/playground)中尝试在线 Svelte,或者如果您需要一个功能更全面的开发环境,可以在[StackBlitz](https://sveltekit.new)上使用。 # Getting started We recommend using [SvelteKit](../kit), which lets you [build almost anything](../kit/project-types). It's the official application framework from the Svelte team and powered by [Vite](https://vite.dev/). Create a new project with: ```bash npx sv create myapp cd myapp npm install npm run dev ``` Don't worry if you don't know Svelte yet! You can ignore all the nice features SvelteKit brings on top for now and dive into it later. ## Alternatives to SvelteKit You can also use Svelte directly with Vite by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS, and CSS files inside the `dist` directory using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well. > \[!NOTE\] Vite is often used in standalone mode to build [single page apps (SPAs)](../kit/glossary#SPA), which you can also [build with SvelteKit](../kit/single-page-apps). There are also plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins), but we recommend Vite. ## Editor tooling The Svelte team maintains a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), and there are integrations with various other [editors](https://sveltesociety.dev/resources#editor-support) and tools as well. You can also check your code from the command line using [sv check](https://github.com/sveltejs/cli). ## Getting help Don't be shy about asking for help in the [Discord chatroom](/chat)! You can also find answers on [Stack Overflow](https://stackoverflow.com/questions/tagged/svelte). # .svelte files Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML. All three sections — script, styles and markup — are optional. ```svelte /// file: MyComponent.svelte ``` ## ` ``` You can `export` bindings from this block, and they will become exports of the compiled module. You cannot `export default`, since the default export is the component itself. > \[!NOTE\] If you are using TypeScript and import such exports from a `module` block into a `.ts` file, make sure to have your editor setup so that TypeScript knows about them. This is the case for our VS Code extension and the IntelliJ plugin, but in other cases you might need to setup our [TypeScript editor plugin](https://www.npmjs.com/package/typescript-svelte-plugin). > \[!LEGACY\] In Svelte 4, this script tag was created using ` ``` 与您可能遇到的其他框架不同,没有用于与状态交互的 API —— `count` 只是一个数字,而不是一个对象或函数,您可以像更新任何其他变量一样更新它。 深层政府 如果使用 `$state` 与数组或简单对象一起,结果将是一个深度响应的 *状态代理*。 [代理](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) 允许 Svelte 在读取或写入属性时运行代码,包括通过 `array.push(...)` 等方法,从而触发细粒度更新。 状态递归代理,直到 Svelte 找到除了数组或简单对象(如类或使用`Object.create`创建的对象)之外的内容。在这种情况下... ```js let todos = $state([ { done: false, text: 'add more todos' } ]); ``` 修改单个待办事项的属性将触发依赖于该特定属性的 UI 中任何内容的更新: ```js let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- todos[0].done = !todos[0].done; ``` 如果您向数组中推送一个新的对象,它也将被代理: ```js let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- todos.push({ done: false, text: 'eat lunch' }); ``` > \[!注意\] 当您更新代理属性时,原始对象*不会被*修改。如果您需要在状态代理中使用自己的代理处理器,[您应该在将对象*包装*在`$state`](https://svelte.dev/playground/hello-world?version=latest#H4sIAAAAAAAACpWR3WoDIRCFX2UqhWyIJL3erAulL9C7XnQLMe5ksbUqOpsfln33YuyGFNJC8UKdc2bOhw7Myk9kJXsJ0nttO9jcR5KEG9AWJDwHdzwxznbaYGTl68Do5JM_FRifuh-9X8Y9Gkq1rYx4q66cJbQUWcmqqIL2VDe2IYMEbvuOikBADi-GJDSkXG-phId0G-frye2DO2psQYDFQ0Ys8gQO350dUkEydEg82T0GOs0nsSG9g2IqgxACZueo2ZUlpdvoDC6N64qsg1QKY8T2bpZp8gpIfbCQ85Zn50Ud82HkeY83uDjspenxv3jXcSDyjPWf9L1vJf0GH666J-jLu1ery4dV257IWXBWGa0-xFDMQdTTn2ScxWKsn86ROsLwQxqrVR5QM84Ij8TKFD2-cUZSm4O2LSt30kQcvwCgCmfZnAIAAA==)之后进行包装。 请注意,如果您解构一个响应式值,引用将不会是响应式的——就像在常规 JavaScript 中一样,它们在解构点被评估: ```js let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- let { done, text } = todos[0]; // this will not affect the value of `done` todos[0].done = !todos[0].done; ``` 类 类实例不会被代理。相反,您可以在类字段(无论是公共的还是私有的)中使用 `$state`,或者在 `constructor` 内部立即将属性赋值为第一个赋值: ```js // @errors: 7006 2554 class Todo { done = $state(false); constructor(text) { this.text = $state(text); } reset() { this.text = ''; this.done = false; } } ``` > \[注意\] 编译器将 `done` 和 `text` 转换为类原型的 `get`/`set` 方法,引用私有字段。这意味着属性不可枚举。 在调用 JavaScript 中的方法时,[`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)的值很重要。这不会工作,因为`this`在`reset`方法中将是` ``` 您可以使用内联函数... ```svelte ``` ...或在使用类定义时使用箭头函数: ```js // @errors: 7006 2554 class Todo { done = $state(false); constructor(text) { this.text = $state(text); } +++reset = () => {+++ this.text = ''; this.done = false; } } ``` 内建类 Svelte 提供了内置类如`Set`、`Map`、`Date`和`URL`的反应式实现,可以从[`svelte/reactivity`](svelte-reactivity)导入。 ## `$state.raw` 在您不希望对象和数组深度响应式的情况下,可以使用`$state.raw`。 状态声明为 `$state.raw` 无法修改;它只能 *重新分配*。换句话说,如果您想更新它,而不是分配给对象的属性或使用数组方法如 `push`,请完全替换对象或数组: ```js let person = $state.raw({ name: 'Heraclitus', age: 49 }); // this will have no effect person.age += 1; // this will work, because we're creating a new person person = { name: 'Heraclitus', age: 50 }; ``` 这可以改善大型数组和对象(您本来就不打算修改的)的性能,因为它避免了使它们变为响应式的成本。请注意,原始状态可以*包含*响应式状态(例如,响应式对象的原始数组)。 与`$state`一样,您可以使用`$state.raw`声明类字段。 ## `$state.snapshot` 要获取一个深度响应式代理`$state`的静态快照,请使用`$state.snapshot`: ```svelte ``` 这是一个方便的情况,当你想要将一些状态传递给一个不期望代理的外部库或 API 时,例如 `structuredClone`。 传入状态到函数 JavaScript 是一种 *按值传递* 的语言——当你调用一个函数时,参数是 *值* 而不是 *变量*。换句话说: ```js /// file: index.js // @filename: index.js // ---cut--- /** * @param {number} a * @param {number} b */ function add(a, b) { return a + b; } let a = 1; let b = 2; let total = add(a, b); console.log(total); // 3 a = 3; b = 4; console.log(total); // still 3! ``` 如果`add`想要访问`a`和`b`的*当前*值,并返回当前的`总计`值,您需要使用函数: ```js /// file: index.js // @filename: index.js // ---cut--- /** * @param {() => number} getA * @param {() => number} getB */ function add(+++getA, getB+++) { return +++() => getA() + getB()+++; } let a = 1; let b = 2; let total = add+++(() => a, () => b)+++; console.log(+++total()+++); // 3 a = 3; b = 4; console.log(+++total()+++); // 7 ``` 状态在 Svelte 中并无不同——当你引用使用`$state`符声明的某个内容时... ```js let a = +++$state(1)+++; let b = +++$state(2)+++; ``` ...您正在访问其*当前值*。 请注意,“函数”概念很广泛——它包括代理属性以及 [`get`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) 属性... ```js /// file: index.js // @filename: index.js // ---cut--- /** * @param {{ a: number, b: number }} input */ function add(input) { return { get value() { return input.a + input.b; } }; } let input = $state({ a: 1, b: 2 }); let total = add(input); console.log(total.value); // 3 input.a = 3; input.b = 4; console.log(total.value); // 7 ``` ...尽管如果你发现自己正在编写那样的代码,考虑使用[类](#Classes)代替。 模块间传递状态 您可以在`.svelte.js`和`.svelte.ts`文件中声明状态,但只有在该状态未被直接重新赋值时才能*导出*该状态。换句话说,您不能这样做: ```js /// file: state.svelte.js export let count = $state(0); export function increment() { count += 1; } ``` 这是因为对`count`的每一个引用都会被 Svelte 编译器转换——上面的代码大致等同于以下内容: ```js /// file: state.svelte.js (compiler output) // @filename: index.ts interface Signal { value: T; } interface Svelte { state(value?: T): Signal; get(source: Signal): T; set(source: Signal, value: T): void; } declare const $: Svelte; // ---cut--- export let count = $.state(0); export function increment() { $.set(count, $.get(count) + 1); } ``` > \[!注意\] 您可以通过点击“JS 输出”标签在 [沙盒](/playground) 中查看 Svelte 生成的代码。 由于编译器一次只处理一个文件,如果另一个文件导入 `count`,Svelte 就不知道需要将每个引用包裹在 `$.get` 和 `$.set` 中: ```js // @filename: state.svelte.js export let count = 0; // @filename: index.js // ---cut--- import { count } from './state.svelte.js'; console.log(typeof count); // 'object', not 'number' ``` 这使您在模块之间共享状态时有两个选项——要么不重新分配它... ```js // This is allowed — since we're updating // `counter.count` rather than `counter`, // Svelte doesn't wrap it in `$.state` export const counter = $state({ count: 0 }); export function increment() { counter.count += 1; } ``` ...或不要直接导出: ```js let count = $state(0); export function getCount() { return count; } export function increment() { count += 1; } ``` # $derived 派生状态使用 `$derived` 符号声明: ```svelte

{count} doubled is {doubled}

``` 表达式内部 `$derived(...)` 应当无副作用。Svelte 将禁止在派生表达式中进行状态更改(例如 `count++`)。 与`$state`一样,您可以标记类字段为`$derived`。 > \[注意\] Svelte 组件中的代码仅在创建时执行一次。如果没有`$derived`运行,`doubled`即使在`count`变化时也会保持其原始值。 ## `$derived.by` 有时您需要创建不适合简短表达式的复杂推导。在这种情况下,您可以使用`$derived.by`,它接受一个函数作为其参数。 ```svelte ``` 本质上,`$derived(expression)` 等同于 `$derived.by(() => expression)`。 ## 理解依赖关系 任何在 `$derived` 表达式(或 `$derived.by` 函数体)内同步读取的内容都被视为派生状态的 *依赖*。当状态发生变化时,派生状态将被标记为 *脏*,并在下一次读取时重新计算。 为将某个状态从依赖项处理中豁免,请使用 [`untrack`](svelte#untrack)。 ## 覆盖派生值 派生表达式在其依赖项更改时会被重新计算,但您可以通过重新分配它们来临时覆盖它们的值(除非它们被声明为`const`)。这可以用于诸如*乐观的用户界面*等情况,其中值是从“真相来源”(例如您的服务器上的数据)派生出来的,但您希望向用户显示即时反馈: ```svelte ``` > \[注意\] 在 Svelte 5.25 之前,派生变量是只读的。 ## 派生和反应性 不同于`$state`,它将对象和数组转换为[深度响应式代理,`$derived`值保持原样。例如,]($state#Deep-state)[在这种情况下...](/REMOVED) ```svelte let items = $state([...]); let index = $state(0); let selected = $derived(items[index]); ``` ...您可以更改(或 `绑定:`)`选定的`属性,这将影响底层的`items`数组。如果`items`不是*深度响应式*的,修改`selected`将没有效果。 ## 解构 如果您使用与`$derived`声明一起的解构,则生成的所有变量都将具有响应性——这... ```js function stuff() { return { a: 1, b: 2, c: 3 } } // ---cut--- let { a, b, c } = $derived(stuff()); ``` ...大致相当于这个: ```js function stuff() { return { a: 1, b: 2, c: 3 } } // ---cut--- let _stuff = $derived(stuff()); let a = $derived(_stuff.a); let b = $derived(_stuff.b); let c = $derived(_stuff.c); ``` ## 更新传播 Svelte 使用一种称为*推拉响应性*的技术——当状态更新时,所有依赖于状态(无论是直接还是间接)的内容都会立即收到变更通知(即“推”),但派生值不会在实际上读取之前重新评估(即“拉”)。 如果派生值与其之前的值在引用上相同,则将跳过下游更新。换句话说,只有当 `large` 发生变化时,Svelte 才会更新按钮内的文本,而不是当 `count` 发生变化时,即使 `large` 依赖于 `count`: ```svelte ``` # $effect 效果是当状态更新时运行的函数,可用于调用第三方库、在`元素上绘图或发起网络请求。它们仅在浏览器中运行,不在服务器端渲染期间运行。` 一般来说,你应*不要*在效果中更新状态,因为这会使代码更加复杂,并常常导致无限循环更新。如果你发现自己正在这样做,请参阅[何时不应使用`$effect`](#When-not-to-use-$effect)以了解替代方法。 您可以使用`$effect`符文([演示](/REMOVED))创建效果: ```svelte ``` 當 Svelte 运行效果函数時,它會追踪哪些狀態(以及導出狀態)被訪問(除非在 [`untrack`](svelte#untrack) 內部訪問),當該狀態之後發生變化時,會重新運行該函數。 > \[!注意\] 如果您难以理解为什么您的 `$effect` 重新运行或没有运行,请参阅 [理解依赖关系](#Understanding-dependencies)。与您从 Svelte 4 过来可能习惯的 `$:` 块相比,效果触发方式不同。 ### 理解生命周期 您的效果在组件挂载到 DOM 之后运行,并在状态变化后的一个[微任务](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide)中运行。重新运行是分批进行的(即在同一时刻更改`颜色`和`大小`不会导致两次单独的运行),并且发生在任何 DOM 更新之后。 您可以在任何地方使用`$effect`,而不仅仅是组件的顶层,只要在父级效果运行时调用即可。 > \[!注意\] Svelte 在模板内部使用效果来表示逻辑和表达式 — 这就是当 `

hello {name}!

` 更新时 `name` 发生变化的方式。 一个效果可以返回一个在效果重新运行前立即执行的 *拆卸函数*([演示](/REMOVED))。 ```svelte

{count}

``` 拆解函数在效果被销毁时也会运行,这发生在其父级被销毁(例如,组件被卸载)或父级效果重新运行时。 ### 理解依赖关系 `$effect` 自动获取其函数体内(包括间接地,通过函数调用)同步读取的任何响应式值(`$state`、`$derived`、`$props`)并将它们注册为依赖项。当这些依赖项发生变化时,`$effect` 将安排重新运行。 如果直接在 `$effect` 中使用 `$state` 和 `$derived`(例如,在创建一个 [reactive 类](https://svelte.dev/docs/svelte/$state#Classes) 时),这些值将 *不会被* 作为依赖项处理。 值在异步读取*(例如,在`await`之后或`setTimeout`内部)时不会被跟踪。在此,当`color`改变时,画布将被重绘,但`size`改变时不会([演示](/REMOVED)):* ```ts // @filename: index.ts declare let canvas: { width: number; height: number; getContext(type: '2d', options?: CanvasRenderingContext2DSettings): CanvasRenderingContext2D; }; declare let color: string; declare let size: number; // ---cut--- $effect(() => { const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); // this will re-run whenever `color` changes... context.fillStyle = color; setTimeout(() => { // ...but not when `size` changes context.fillRect(0, 0, size, size); }, 0); }); ``` 仅当读取的对象发生变化时,效果才会重新运行,而不是当它内部的属性发生变化时。(如果您想在开发时观察对象内部的更改,可以使用[`$inspect`]($inspect)。) ```svelte

{state.value} doubled is {derived.value}

``` 一个效果只依赖于它上次运行时读取的值。这对具有条件代码的效果有有趣的含义。 例如,如果以下代码片段中的`condition`是`true`,则`if`块内的代码将执行,并且`color`将被评估。因此,对`condition`或`color`[的更改将导致效果重新运行。](/REMOVED) 相反,如果 `条件` 是 `假`,`颜色` 将不会被评估,并且效果将 *仅* 在 `条件` 发生变化时再次运行。 ```ts // @filename: ambient.d.ts declare module 'canvas-confetti' { interface ConfettiOptions { colors: string[]; } function confetti(opts?: ConfettiOptions): void; export default confetti; } // @filename: index.js // ---cut--- import confetti from 'canvas-confetti'; let condition = $state(true); let color = $state('#ff3e00'); $effect(() => { if (condition) { confetti({ colors: [color] }); } else { confetti(); } }); ``` ## `$effect.pre` 在罕见情况下,您可能需要在 DOM 更新之前运行代码*。*为此,我们可以使用`$effect.pre`符文: ```svelte
{#each messages as message}

{message}

{/each}
``` 除了时间之外,`$effect.pre` 的功能与 `$effect` 完全相同。 ## `$effect.tracking` The `$effect.tracking` 符文是一个高级功能,它告诉您代码是否在跟踪上下文中运行,例如在效果或您的模板中([示例](/REMOVED)): ```svelte

in template: {$effect.tracking()}

``` 用于实现如 [`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber) 这样的抽象,这将创建监听器以更新响应式值,但 *仅* 当这些值正在被跟踪(而不是,例如,在事件处理程序内部读取)时。 ## `$effect.pending` 当在组件中使用[`await`](await-expressions)时,`$effect.pending()`函数告诉你当前[边界](svelte-boundary)(不包括子边界[示例](/REMOVED))中有多少个待处理的承诺: ```svelte

{a} + {b} = {await add(a, b)}

{#if $effect.pending()}

pending promises: {$effect.pending()}

{/if} ``` ## `$effect.root` The `$effect.root` 符文是一个高级功能,它创建一个非跟踪作用域,不会自动清理。这对于您想手动控制嵌套效果非常有用。此符文还允许在组件初始化阶段之外创建效果。 ```js const destroy = $effect.root(() => { $effect(() => { // setup }); return () => { // cleanup }; }); // later... destroy(); ``` ## 當何時不使用`$effect` 通常,`$effect`最好被视为一种逃生门——适用于像分析和对 DOM 的直接操作这样的用途——而不是你应该频繁使用的工具。特别是,避免用它来同步状态。而不是这样做…… ```svelte ``` ...这样做: ```svelte ``` > \[!注意\] 对于比简单表达式如`count * 2`更复杂的情况,您也可以使用`$derived.by`。 如果您使用效果是因为您想要能够重新分配派生值(例如构建乐观的用户界面),请注意,从 Svelte 5.25 开始,[派生值]($derived#Overriding-derived-values)可以直接覆盖。 您可能会想用一些复杂的效果将一个值链接到另一个值。以下示例显示了两个输入:“花费的金额”和“剩余的金额”,它们彼此相连。如果您更新其中一个,另一个也应该相应更新。不要为此使用效果([演示](/REMOVED)): ```svelte ``` 相反,使用`oninput`回调或——更好的选择——尽可能使用[函数绑定](bind#Function-bindings)([演示](/REMOVED)): ```svelte ``` 如果您绝对需要在效果中更新`$state`并遇到无限循环,因为您读取和写入相同的`$state`,请使用[untrack](svelte#untrack)。 # $props 组件的输入被称为*props*,这是*properties*的简称。您向组件传递 props 的方式就像向元素传递属性一样: ```svelte ``` 在另一方面,在`MyComponent.svelte`内部,我们可以通过`$props`属性接收 props... ```svelte

this component is {props.adjective}

``` ...尽管更常见的是,你会[*解构*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)你的 props: ```svelte

this component is {+++adjective+++}

``` 回退值 解构允许我们声明回退值,这些值在父组件未设置给定属性(或值是 `undefined`)时使用: ```js let { adjective = 'happy' } = $props(); ``` > \[!注意\] 回退值不会被转换为响应式状态代理(有关更多信息,请参阅[更新属性](#Updating-props)) 重命名属性 我们还可以使用解构赋值来重命名 props,这在它们是无效标识符或 JavaScript 关键字(如`super`)时是必要的: ```js let { super: trouper = 'lights are gonna find me' } = $props(); ``` ## Rest props 最后,我们可以使用一个 *剩余属性* 来获取,嗯,其余的 props: ```js let { a, b, c, ...others } = $props(); ``` 更新属性 组件内部属性更新时对属性的引用也会更新——当 `count` 在 `App.svelte` 中变化时,它也会在 `Child.svelte` 中变化。但子组件可以临时覆盖属性值,这在处理未保存的短暂状态时可能很有用([演示](/REMOVED))。 ```svelte ``` ```svelte ``` 虽然您可以临时重新分配属性,但除非它们是可绑定的,否则您不应该修改属性。 如果属性是一个普通对象,则变异将没有效果([demo](/REMOVED)): ```svelte ``` ```svelte ``` 如果属性是一个响应式状态代理,那么突变*将*产生影响,但你会看到一个[`ownership_invalid_mutation`](runtime-warnings#Client-warnings-ownership_invalid_mutation)警告,因为组件正在修改不属于它的状态([demo](/REMOVED)): ```svelte ``` ```svelte ``` 备用值的属性未使用`$bindable`声明时保持不变——它不会被转换为响应式状态代理——这意味着变更不会引起更新([示例](/REMOVED)) ```svelte ``` 总结:不要修改 props。要么使用回调 props 来传递变化,或者——如果父元素和子元素应该共享同一个对象——使用[`$bindable`]($bindable) rune。 类型安全 您可以通过注释您的 props 来为组件添加类型安全,就像您对任何其他变量声明一样。在 TypeScript 中,这可能看起来像这样... ```svelte ``` ...當在 JSDoc 中可以這樣做: ```svelte ``` 当然,您可以将类型声明与注解分开: ```svelte ``` > \[!注意\] 本地 DOM 元素的接口在`svelte/elements`模块中提供(见[类型包装组件](typescript#Typing-wrapper-components)) 添加类型是推荐的,因为它确保使用您组件的人可以轻松地发现他们应该提供哪些属性。 ## `$props.id()` 此符文自 5.20.0 版本添加,生成一个仅对当前组件实例唯一的 ID。在服务器端渲染的组件中,该值将在服务器和客户端之间保持一致。 这对于通过属性如`for`和`aria-labelledby`链接元素很有用。 ```svelte
``` # $bindable Ordinarily, props go one way, from parent to child. This makes it easy to understand how data flows around your app. In Svelte, component props can be *bound*, which means that data can also flow *up* from child to parent. This isn't something you should do often, but it can simplify your code if used sparingly and carefully. It also means that a state proxy can be *mutated* in the child. > \[!NOTE\] Mutation is also possible with normal props, but is strongly discouraged — Svelte will warn you if it detects that a component is mutating state it does not 'own'. To mark a prop as bindable, we use the `$bindable` rune: ```svelte /// file: FancyInput.svelte ``` Now, a component that uses `` can add the [`bind:`](bind) directive ([demo](/REMOVED)): ```svelte /// file: App.svelte

{message}

``` The parent component doesn't *have* to use `bind:` — it can just pass a normal prop. Some parents don't want to listen to what their children have to say. In this case, you can specify a fallback value for when no prop is passed at all: ```js /// file: FancyInput.svelte let { value = $bindable('fallback'), ...props } = $props(); ``` # $inspect > \[!NOTE\] `$inspect` only works during development. In a production build it becomes a noop. The `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its argument changes. `$inspect` tracks reactive state deeply, meaning that updating something inside an object or array using fine-grained reactivity will cause it to re-fire ([demo](/REMOVED)): ```svelte ``` ## $inspect(...).with `$inspect` returns a property `with`, which you can invoke with a callback, which will then be invoked instead of `console.log`. The first argument to the callback is either `"init"` or `"update"`; subsequent arguments are the values passed to `$inspect` ([demo](/REMOVED)): ```svelte ``` A convenient way to find the origin of some change is to pass `console.trace` to `with`: ```js // @errors: 2304 $inspect(stuff).with(console.trace); ``` ## $inspect.trace(...) This rune, added in 5.14, causes the surrounding function to be *traced* in development. Any time the function re-runs as part of an [effect]($effect) or a [derived]($derived), information will be printed to the console about which pieces of reactive state caused the effect to fire. ```svelte ``` `$inspect.trace` takes an optional first argument which will be used as the label. # $host When compiling a component as a [custom element](custom-elements), the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](/REMOVED)): ```svelte /// file: Stepper.svelte ``` ```svelte /// file: App.svelte count -= 1} onincrement={() => count += 1} >

count: {count}

``` # Basic markup 组件内的标记可以被视为 HTML++。 ## 标签 一个小写标签,如`
`,表示一个常规 HTML 元素。一个大写标签或使用点符号的标签,例如``或``,表示一个*组件*。 ```svelte
``` ## 元素属性 默认情况下,属性与它们的 HTML 对应项完全相同。 ```svelte
``` 与 HTML 一样,值可能未加引号。 `<input type=checkbox />` 属性值可以包含 JavaScript 表达式。 ```svelte page {p} ``` 或者它们可以是 *JavaScript 表达式*。 ```svelte ``` 布尔属性在元素上包含,如果它们的值是[真值](https://developer.mozilla.org/en-US/docs/Glossary/Truthy),如果它们是[假值](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)则排除。 所有其他属性都包含在内,除非它们的值为[空值](https://developer.mozilla.org/en-US/docs/Glossary/Nullish)(`null`或`undefined`)。 ```svelte
This div has no title attribute
``` > \[注意\] 引用单个表达式不会影响值的解析方式,但在 Svelte 6 中,它将导致值被强制转换为字符串: > > ```svelte > > ``` 當屬性名稱和值匹配(`name={name}`)時,它們可以與`{name}`替換。 ```svelte ``` ## 组件属性 按照惯例,传递给组件的值被称为*属性*或*props*,而不是*属性*,后者是 DOM 的一个特性。 与元素一样,`name={name}` 可以用 `{name}` 简写代替。 ```svelte ``` ## 扩展属性 *扩展属性*允许一次性将许多属性或属性传递给一个元素或组件。 一个元素或组件可以拥有多个扩展属性,这些属性与常规属性交错。顺序很重要——如果存在 `things.a`,则它将优先于 `a="b"`,而 `c="d"` 将优先于 `things.c`: ```svelte ``` ## 事件 监听 DOM 事件可以通过向元素添加以`on`开头的属性来实现。例如,要监听`click`事件,请向按钮添加`onclick`属性: ```svelte ``` 事件属性区分大小写。\``onclick`\` 监听 \``click`\` 事件,\``onClick`\` 监听 \``Click`\` 事件,这是不同的。这确保您可以监听包含大写字母的自定义事件。 因为事件只是属性,所以适用于属性的规则同样适用: * 您可以使用缩写形式: `` * 你可以将它们传播: `` 时间上,事件属性总是在绑定的事件之后触发(例如,`oninput` 总是在 `bind:value` 更新之后触发)。底层中,一些事件处理器直接通过 `addEventListener` 绑定,而另一些则是 *委托* 的。 当使用`ontouchstart`和`ontouchmove`事件属性时,处理程序是[passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners)以获得更好的性能。这大大提高了响应速度,允许浏览器立即滚动文档,而不是等待查看事件处理程序是否调用`event.preventDefault()`。 在极少数需要防止这些事件默认行为的情况下,您应该使用 [`on`](svelte-events#on) 代替(例如在操作中)。 ### 事件委托 为了减少内存占用并提高性能,Svelte 使用了一种称为事件委托的技术。这意味着对于某些事件——请参阅以下列表——应用程序根目录下的单个事件监听器负责处理事件路径上的任何处理程序。 有一些需要注意的陷阱: * 当你手动派发一个带有委托监听器的事件时,请确保设置`{ bubbles: true }`选项,否则它不会到达应用程序根目录 * 当直接使用`addEventListener`时,请避免调用`stopPropagation`,否则事件将无法到达应用程序根节点,处理程序也不会被调用。同样,在应用程序根节点内部手动添加的处理程序将在 DOM 中声明性更深处的处理程序(例如,使用`onclick={...}`)之前运行*before*,在捕获和冒泡阶段都如此。因此,最好使用从`svelte/events`导入的`on`函数,而不是使用`addEventListener`,因为它将确保顺序得到保留,并且正确处理`stopPropagation`。 以下事件处理程序被委派: * `输入之前` * `点击` * `更改` * `dblclick` * `上下文菜单` * `focusin` * `focusout` * `输入` * `keydown` * `keyup` * `mousedown` * `mousemove` * `mouseout` * `mouseover` * `mouseup` * `pointerdown` * `pointermove` * `指针出` * `pointerover` * `pointerup` * `touchend` * `touchmove` * `touchstart` ## 文本表达式 一个 JavaScript 表达式可以通过用花括号包围它来作为文本包含。 `{表达式}` 表达式为`null`或`undefined`的将被省略;其余所有表达式都将被强制转换为字符串。[转换为字符串](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion)。 花括号可以通过使用它们的 HTML 实体字符串在 Svelte 模板中包含:用于`{`的`{`、`{`或`{`,以及用于`}`的`}`、`}`或`}`。 如果您使用的是正则表达式(`RegExp`)[字面表示法](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#literal_notation_and_constructor),您需要将其括在括号内。 ```svelte

Hello {name}!

{a} + {b} = {a + b}.

{(/^[A-Za-z ]+$/).test(value) ? x : y}
``` 表达式将被转换为字符串并转义,以防止代码注入。如果您想渲染 HTML,请使用`{@html}`标签。 ```svelte {@html potentiallyUnsafeHtmlString} ``` > \[!注意\] 确保您要么转义传递的字符串,要么只填充您控制的值,以防止[XSS 攻击](https://owasp.org/www-community/attacks/xss/) ## 注释 您可以在组件内部使用 HTML 注释。 ```svelte

Hello world

``` 注释以`svelte-ignore`开始的代码禁用后续标记块的警告。通常,这些是可访问性警告;请确保您有充分的理由来禁用它们。 ```svelte ``` 您可以在注释中添加以`@component`开头的特殊注释,当在其他文件中悬停到组件名称上时,该注释将显示出来。 ```svelte

Hello, {name}

``` # {#if ...} ```svelte {#if expression}...{/if} ``` ```svelte {#if expression}...{:else if expression}...{/if} ``` ```svelte {#if expression}...{:else}...{/if} ``` Content that is conditionally rendered can be wrapped in an if block. ```svelte {#if answer === 42}

what was the question?

{/if} ``` Additional conditions can be added with `{:else if expression}`, optionally ending in an `{:else}` clause. ```svelte {#if porridge.temperature > 100}

too hot!

{:else if 80 > porridge.temperature}

too cold!

{:else}

just right!

{/if} ``` (Blocks don't have to wrap elements, they can also wrap text within elements.) # {#each ...} ```svelte {#each expression as name}...{/each} ``` ```svelte {#each expression as name, index}...{/each} ``` Iterating over values can be done with an each block. The values in question can be arrays, array-like objects (i.e. anything with a `length` property), or iterables like `Map` and `Set` — in other words, anything that can be used with `Array.from`. ```svelte

Shopping list

    {#each items as item}
  • {item.name} x {item.qty}
  • {/each}
``` An each block can also specify an _index_, equivalent to the second argument in an `array.map(...)` callback: ```svelte {#each items as item, i}
  • {i + 1}: {item.name} x {item.qty}
  • {/each} ``` ## Keyed each blocks ```svelte {#each expression as name (key)}...{/each} ``` ```svelte {#each expression as name, index (key)}...{/each} ``` If a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to intelligently update the list when data changes by inserting, moving and deleting items, rather than adding or removing items at the end and updating the state in the middle. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change. ```svelte {#each items as item (item.id)}
  • {item.name} x {item.qty}
  • {/each} {#each items as item, i (item.id)}
  • {i + 1}: {item.name} x {item.qty}
  • {/each} ``` You can freely use destructuring and rest patterns in each blocks. ```svelte {#each items as { id, name, qty }, i (id)}
  • {i + 1}: {name} x {qty}
  • {/each} {#each objects as { id, ...rest }}
  • {id}
  • {/each} {#each items as [id, ...rest]}
  • {id}
  • {/each} ``` ## Each blocks without an item ```svelte {#each expression}...{/each} ``` ```svelte {#each expression, index}...{/each} ``` In case you just want to render something `n` times, you can omit the `as` part ([demo](/REMOVED)): ```svelte
    {#each { length: 8 }, rank} {#each { length: 8 }, file}
    {/each} {/each}
    ``` ## Else blocks ```svelte {#each expression as name}...{:else}...{/each} ``` An each block can also have an `{:else}` clause, which is rendered if the list is empty. ```svelte {#each todos as todo}

    {todo.text}

    {:else}

    No tasks today!

    {/each} ``` # {#key ...} ```svelte {#key expression}...{/key} ``` Key blocks destroy and recreate their contents when the value of an expression changes. When used around components, this will cause them to be reinstantiated and reinitialised: ```svelte {#key value} {/key} ``` It's also useful if you want a transition to play whenever a value changes: ```svelte {#key value}
    {value}
    {/key} ``` # {#await ...} ```svelte {#await expression}...{:then name}...{:catch name}...{/await} ``` ```svelte {#await expression}...{:then name}...{/await} ``` ```svelte {#await expression then name}...{/await} ``` ```svelte {#await expression catch name}...{/await} ``` Await blocks allow you to branch on the three possible states of a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled or rejected. ```svelte {#await promise}

    waiting for the promise to resolve...

    {:then value}

    The value is {value}

    {:catch error}

    Something went wrong: {error.message}

    {/await} ``` > > If the provided expression is not a `Promise`, only the `:then` branch will be rendered, including during server-side rendering. The `catch` block can be omitted if you don't need to render anything when the promise rejects (or no error is possible). ```svelte {#await promise}

    waiting for the promise to resolve...

    {:then value}

    The value is {value}

    {/await} ``` If you don't care about the pending state, you can also omit the initial block. ```svelte {#await promise then value}

    The value is {value}

    {/await} ``` Similarly, if you only want to show the error state, you can omit the `then` block. ```svelte {#await promise catch error}

    The error is {error}

    {/await} ``` > > ```svelte > {#await import('./Component.svelte') then { default: Component }} > > {/await} > ``` # {#snippet ...} ```svelte {#snippet name()}...{/snippet} ``` ```svelte {#snippet name(param1, param2, paramN)}...{/snippet} ``` Snippets, and [render tags](@render), are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](/REMOVED)... ```svelte {#each images as image} {#if image.href}
    {image.caption}
    {image.caption}
    {:else}
    {image.caption}
    {image.caption}
    {/if} {/each} ``` ...you can write [this](/REMOVED): ```svelte {#snippet figure(image)}
    {image.caption}
    {image.caption}
    {/snippet} {#each images as image} {#if image.href} {@render figure(image)} {:else} {@render figure(image)} {/if} {/each} ``` Like function declarations, snippets can have an arbitrary number of parameters, which can have default values, and you can destructure each parameter. You cannot use rest parameters, however. ## Snippet scope Snippets can be declared anywhere inside your component. They can reference values declared outside themselves, for example in the ` {#snippet hello(name)}

    hello {name}! {message}!

    {/snippet} {@render hello('alice')} {@render hello('bob')} ``` ...and they are 'visible' to everything in the same lexical scope (i.e. siblings, and children of those siblings): ```svelte
    {#snippet x()} {#snippet y()}...{/snippet} {@render y()} {/snippet} {@render y()}
    {@render x()} ``` Snippets can reference themselves and each other ([demo](/REMOVED)): ```svelte {#snippet blastoff()} 🚀 {/snippet} {#snippet countdown(n)} {#if n > 0} {n}... {@render countdown(n - 1)} {:else} {@render blastoff()} {/if} {/snippet} {@render countdown(10)} ``` ## Passing snippets to components ### Explicit props Within the template, snippets are values just like any other. As such, they can be passed to components as props ([demo](/REMOVED)): ```svelte {#snippet header()} fruit qty price total {/snippet} {#snippet row(d)} {d.name} {d.qty} {d.price} {d.qty * d.price} {/snippet} ``` Think about it like passing content instead of data to a component. The concept is similar to slots in web components. ### Implicit props As an authoring convenience, snippets declared directly _inside_ a component implicitly become props _on_ the component ([demo](/REMOVED)): ```svelte
    {#snippet header()} {/snippet} {#snippet row(d)} {/snippet}
    fruit qty price total{d.name} {d.qty} {d.price} {d.qty * d.price}
    ``` ### Implicit `children` snippet Any content inside the component tags that is _not_ a snippet declaration implicitly becomes part of the `children` snippet ([demo](/REMOVED)): ```svelte ``` ```svelte ``` ### Optional snippet props You can declare snippet props as being optional. You can either use optional chaining to not render anything if the snippet isn't set... ```svelte {@render children?.()} ``` ...or use an `#if` block to render fallback content: ```svelte {#if children} {@render children()} {:else} fallback content {/if} ``` ## Typing snippets Snippets implement the `Snippet` interface imported from `'svelte'`: ```svelte ``` With this change, red squigglies will appear if you try and use the component without providing a `data` prop and a `row` snippet. Notice that the type argument provided to `Snippet` is a tuple, since snippets can have multiple parameters. We can tighten things up further by declaring a generic, so that `data` and `row` refer to the same type: ```svelte ``` ## Exporting snippets Snippets declared at the top level of a `.svelte` file can be exported from a ` {#snippet add(a, b)} {a} + {b} = {a + b} {/snippet} ``` > This requires Svelte 5.5.0 or newer ## Programmatic snippets Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases. ## Snippets and slots In Svelte 4, content can be passed to components using [slots](legacy-slots). Snippets are more powerful and flexible, and as such slots are deprecated in Svelte 5. # {@render ...} To render a [snippet](snippet), use a `{@render ...}` tag. ```svelte {#snippet sum(a, b)}

    {a} + {b} = {a + b}

    {/snippet} {@render sum(1, 2)} {@render sum(3, 4)} {@render sum(5, 6)} ``` The expression can be an identifier like `sum`, or an arbitrary JavaScript expression: ```svelte {@render (cool ? coolSnippet : lameSnippet)()} ``` ## Optional snippets If the snippet is potentially undefined — for example, because it's an incoming prop — then you can use optional chaining to only render it when it _is_ defined: ```svelte {@render children?.()} ``` Alternatively, use an [`{#if ...}`](if) block with an `:else` clause to render fallback content: ```svelte {#if children} {@render children()} {:else}

    fallback content

    {/if} ``` # {@html ...} To inject raw HTML into your component, use the `{@html ...}` tag: ```svelte
    {@html content}
    ``` The expression should be valid standalone HTML — this will not work, because `
    ` is not valid HTML: ```svelte {@html '
    '}content{@html '
    '} ``` It also will not compile Svelte code. ## Styling Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](scoped-styles) — in other words, this will not work, and the `a` and `img` styles will be regarded as unused: ```svelte
    {@html content}
    ``` Instead, use the `:global` modifier to target everything inside the `
    `: ```svelte ``` # {@attach ...} Attachments are functions that run in an [effect]($effect) when an element is mounted to the DOM or when [state]($state) read inside the function updates. Optionally, they can return a function that is called before the attachment re-runs, or after the element is later removed from the DOM. > Attachments are available in Svelte 5.29 and newer. ```svelte
    ...
    ``` An element can have any number of attachments. ## Attachment factories A useful pattern is for a function, such as `tooltip` in this example, to _return_ an attachment ([demo](/REMOVED)): ```svelte ``` Since the `tooltip(content)` expression runs inside an [effect]($effect), the attachment will be destroyed and recreated whenever `content` changes. The same thing would happen for any state read _inside_ the attachment function when it first runs. (If this isn't what you want, see [Controlling when attachments re-run](#Controlling-when-attachments-re-run).) ## Inline attachments Attachments can also be created inline ([demo](/REMOVED)): ```svelte { const context = canvas.getContext('2d'); $effect(() => { context.fillStyle = color; context.fillRect(0, 0, canvas.width, canvas.height); }); }} > ``` > The nested effect runs whenever `color` changes, while the outer effect (where `canvas.getContext(...)` is called) only runs once, since it doesn't read any reactive state. ## Passing attachments to components When used on a component, `{@attach ...}` will create a prop whose key is a [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol). If the component then [spreads](/tutorial/svelte/spread-props) props onto an element, the element will receive those attachments. This allows you to create _wrapper components_ that augment elements ([demo](/REMOVED)): ```svelte ``` ```svelte ``` ## Controlling when attachments re-run Attachments, unlike [actions](use), are fully reactive: `{@attach foo(bar)}` will re-run on changes to `foo` _or_ `bar` (or any state read inside `foo`): ```js // @errors: 7006 2304 2552 function foo(bar) { return (node) => { veryExpensiveSetupWork(node); update(node, bar); }; } ``` In the rare case that this is a problem (for example, if `foo` does expensive and unavoidable setup work) consider passing the data inside a function and reading it in a child effect: ```js // @errors: 7006 2304 2552 function foo(+++getBar+++) { return (node) => { veryExpensiveSetupWork(node); +++ $effect(() => { update(node, getBar()); });+++ } } ``` ## Creating attachments programmatically To add attachments to an object that will be spread onto a component or element, use [`createAttachmentKey`](svelte-attachments#createAttachmentKey). ## Converting actions to attachments If you're using a library that only provides actions, you can convert them to attachments with [`fromAction`](svelte-attachments#fromAction), allowing you to (for example) use them with components. # {@const ...} The `{@const ...}` tag defines a local constant. ```svelte {#each boxes as box} {@const area = box.width * box.height} {box.width} * {box.height} = {area} {/each} ``` `{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — a `` or a ``. # {@debug ...} The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open. ```svelte {@debug user}

    Hello {user.firstname}!

    ``` `{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions). ```svelte {@debug user} {@debug user1, user2, user3} {@debug user.firstname} {@debug myArray[0]} {@debug !isReady} {@debug typeof user === 'object'} ``` The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when _any_ state changes, as opposed to the specified variables. # bind: Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent. The general syntax is `bind:property={expression}`, where `expression` is an [_lvalue_](https://press.rebus.community/programmingfundamentals/chapter/lvalue-and-rvalue/) (i.e. a variable or an object property). When the expression is an identifier with the same name as the property, we can omit the expression — in other words these are equivalent: ```svelte ``` Svelte creates an event listener that updates the bound value. If an element already has a listener for the same event, that listener will be fired before the bound value is updated. Most bindings are _two-way_, meaning that changes to the value will affect the element and vice versa. A few bindings are _readonly_, meaning that changing their value will have no effect on the element. ## Function bindings You can also use `bind:property={get, set}`, where `get` and `set` are functions, allowing you to perform validation and transformation: ```svelte value, (v) => value = v.toLowerCase()} /> ``` In the case of readonly bindings like [dimension bindings](#Dimensions), the `get` value should be `null`: ```svelte
    ...
    ``` > Function bindings are available in Svelte 5.9.0 and newer. ## `` A `bind:value` directive on an `` element binds the input's `value` property: ```svelte

    {message}

    ``` In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number ([demo](/REMOVED)): ```svelte

    {a} + {b} = {a + b}

    ``` If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`. Since 5.6.0, if an `` has a `defaultValue` and is part of a form, it will revert to that value instead of the empty string when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`. ```svelte
    ``` > Use reset buttons sparingly, and ensure that users won't accidentally click them while trying to submit the form. ## `` Checkbox and radio inputs can be bound with `bind:checked`: ```svelte ``` Since 5.6.0, if an `` has a `defaultChecked` attribute and is part of a form, it will revert to that value instead of `false` when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`. ```svelte
    ``` ## `` Checkboxes can be in an [indeterminate](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/indeterminate) state, independently of whether they are checked or unchecked: ```svelte
    {#if indeterminate} waiting... {:else if checked} checked {:else} unchecked {/if}
    ``` ## `` Inputs that work together can use `bind:group` ([demo](/REMOVED)): ```svelte ``` ## `` On `` elements with `type="file"`, you can use `bind:files` to get the [`FileList` of selected files](https://developer.mozilla.org/en-US/docs/Web/API/FileList). When you want to update the files programmatically, you always need to use a `FileList` object. Currently `FileList` objects cannot be constructed directly, so you need to create a new [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object and get `files` from there. ```svelte ``` `FileList` objects also cannot be modified, so if you want to e.g. delete a single file from the list, you need to create a new `DataTransfer` object and add the files you want to keep. ## `` value binding corresponds to the `value` property on the selected ` ``` When the value of an ` ``` ## `