This is the abridged developer documentation for Svelte and SvelteKit. # Start of Svelte documentation # 概述 Svelte 是一个用于在 Web 上构建用户界面的框架。它使用编译器将用 HTML、CSS 和 JavaScript 编写的声明性组件转换为... ¥Svelte is a framework for building user interfaces on the web. It uses a compiler to turn declarative components written in HTML, CSS and JavaScript... ```svelte ``` ...精简、紧密优化的 JavaScript。 ¥...into lean, tightly optimized JavaScript. 你可以使用它在网络上构建任何东西,从独立组件到雄心勃勃的全栈应用(使用 Svelte 的配套应用框架 [SvelteKit](../kit))以及介于两者之间的一切。 ¥You can use it to build anything on the web, from standalone components to ambitious full stack apps (using Svelte's companion application framework, [SvelteKit](../kit)) and everything in between. 这些页面用作参考文档。如果你是 Svelte 新手,我们建议你从 [互动教程](/tutorial) 开始,有问题时再回来这里。 ¥These pages serve as reference documentation. If you're new to Svelte, we recommend starting with the [interactive tutorial](/tutorial) and coming back here when you have questions. 你还可以在 [playground](https://svelte.dev/playground) 中在线试用 Svelte,或者,如果你需要功能更齐全的环境,可以在 [StackBlitz](https://sveltekit.new) 上试用。 ¥You can also try Svelte online in the [playground](https://svelte.dev/playground) or, if you need a more fully-featured environment, on [StackBlitz](https://sveltekit.new). # 立即开始 我们建议使用 [SvelteKit](../kit),这是 Svelte 团队由 [Vite](https://vite.dev/) 提供支持的官方应用框架: ¥We recommend using [SvelteKit](../kit), the official application framework from the Svelte team powered by [Vite](https://vite.dev/): ```bash npx sv create myapp cd myapp npm install npm run dev ``` 如果你还不了解 Svelte,请不要担心!你现在可以忽略 SvelteKit 带来的所有优秀功能,稍后再深入研究。 ¥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. ## SvelteKit 的替代品(Alternatives to SvelteKit) ¥Alternatives to SvelteKit 你还可以通过运行 `npm create vite@latest` 并选择 `svelte` 选项将 Svelte 直接与 Vite 一起使用。通过此方法,`npm run build` 将使用 [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte) 在 `dist` 目录中生成 HTML、JS 和 CSS 文件。在大多数情况下,你可能还需要 [选择路由库](faq#Is-there-a-router)。 ¥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. 还有适用于 [Rollup](https://github.com/sveltejs/rollup-plugin-svelte)、[Webpack](https://github.com/sveltejs/svelte-loader) [以及其他一些](https://sveltesociety.dev/packages?category=build-plugins) 的插件,但我们推荐 Vite。 ¥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) ¥Editor tooling Svelte 团队维护 [VS Code 扩展](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode),并且还与其他各种 [编辑器](https://sveltesociety.dev/resources#editor-support) 和工具集成。 ¥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. 你还可以使用 [sv check](https://github.com/sveltejs/cli) 从命令行检查你的代码。 ¥You can also check your code from the command line using [sv check](https://github.com/sveltejs/cli). ## 寻求帮助(Getting help) ¥Getting help 不要羞于在 [Discord 聊天室](/chat) 中寻求帮助!你还可以在 [Stack Overflow](https://stackoverflow.com/questions/tagged/svelte) 上找到答案。 ¥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 文件 组件是 Svelte 应用的构建块。它们使用 HTML 的超集写入 `.svelte` 文件。 ¥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 ``` ## ` ``` 你可以从此块中 `export` 绑定,它们将成为已编译模块的导出。你不能 `export default`,因为默认导出是组件本身。 ¥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` 只是一个数字,而不是一个对象或函数,你可以像更新任何其他变量一样更新它。 ¥Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable. ### 深度状态(Deep state) ¥Deep state 如果 `$state` 与数组或简单对象一起使用,则结果是一个深度反应状态代理。[代理](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) 允许 Svelte 在你读取或写入属性时运行代码,包括通过 `array.push(...)` 等方法,触发细粒度更新。 ¥If `$state` is used with an array or a simple object, the result is a deeply reactive *state proxy*. [Proxies](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates. > > ¥[!NOTE] Classes like `Set` and `Map` will not be proxied, but Svelte provides reactive implementations for various built-ins like these that can be imported from [`svelte/reactivity`](./svelte-reactivity). 状态被递归代理,直到 Svelte 找到数组或简单对象以外的内容。在这种情况下... ¥State is proxified recursively until Svelte finds something other than an array or simple object. In a case like this... ```js let todos = $state([ { done: false, text: 'add more todos' } ]); ``` ...修改单个待办事项的属性将触发对依赖于该特定属性的 UI 中任何内容的更新: ¥...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property: ```js let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- todos[0].done = !todos[0].done; ``` 如果你将新对象推送到数组,它也将被代理: ¥If you push a new object to the array, it will also be proxified: ```js let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- todos.push({ done: false, text: 'eat lunch' }); ``` > > ¥[!NOTE] When you update properties of proxies, the original object is *not* mutated. 请注意,如果你解构一个反应性值,则引用不是反应性的 - 与普通 JavaScript 一样,它们在解构时进行评估: ¥Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring: ```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; ``` ### 类(Classes) ¥Classes 你还可以在类字段(无论是公共还是私有)中使用 `$state`: ¥You can also use `$state` in class fields (whether public or private): ```js // @errors: 7006 2554 class Todo { done = $state(false); text = $state(); constructor(text) { this.text = text; } reset() { this.text = ''; this.done = false; } } ``` > > ¥[!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable. 在 JavaScript 中调用方法时,[`this`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Operators/this) 的值很重要。这不起作用,因为 `reset` 方法内的 `this` 将是 ` ``` 你可以使用内联函数... ¥You can either use an inline function... ```svelte ``` ...或在类定义中使用箭头函数: ¥...or use an arrow function in the class definition: ```js // @errors: 7006 2554 class Todo { done = $state(false); text = $state(); constructor(text) { this.text = text; } +++reset = () => {+++ this.text = ''; this.done = false; } } ``` ## `$state.raw` 如果你不希望对象和数组具有深度反应性,则可以使用 `$state.raw`。 ¥In cases where you don't want objects and arrays to be deeply reactive you can use `$state.raw`. 用 `$state.raw` 声明的状态无法修改;只能重新分配。换句话说,如果你想要更新对象或数组,则无需将其分配给对象的属性,也不必使用数组方法(如 `push`),而是将其全部替换: ¥State declared with `$state.raw` cannot be mutated; it can only be *reassigned*. In other words, rather than assigning to a property of an object, or using an array method like `push`, replace the object or array altogether if you'd like to update it: ```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 }; ``` 这可以提高你原本不打算修改的大型数组和对象的性能,因为它避免了使它们具有反应性的成本。请注意,原始状态可以包含反应状态(例如,反应对象的原始数组)。 ¥This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can *contain* reactive state (for example, a raw array of reactive objects). ## `$state.snapshot` 要获取深度反应式 `$state` 代理的静态快照,请使用 `$state.snapshot`: ¥To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: ```svelte ``` 当你想要将某些状态传递给不需要代理的外部库或 API(例如 `structuredClone`)时,这很方便。 ¥This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`. ## 将状态传递给函数(Passing state into functions) ¥Passing state into functions JavaScript 是一种按值传递语言 - 当你调用函数时,参数是值而不是变量。换句话说: ¥JavaScript is a *pass-by-value* language — when you call a function, the arguments are the *values* rather than the *variables*. In other words: ```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` 的当前值,并返回当前 `total` 值,则需要使用函数: ¥If `add` wanted to have access to the *current* values of `a` and `b`, and to return the current `total` value, you would need to use functions instead: ```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` 符文声明的内容时…… ¥State in Svelte is no different — when you reference something declared with the `$state` rune... ```js let a = +++$state(1)+++; let b = +++$state(2)+++; ``` ...你正在访问其当前值。 ¥...you're accessing its *current value*. 请注意,'functions' 范围很广 - 它包含代理属性和 [`get`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Functions/set) 属性…… ¥Note that 'functions' is broad — it encompasses properties of proxies and [`get`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Functions/set) properties... ```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](#Classes)。 ¥...though if you find yourself writing code like that, consider using [classes](#Classes) instead. # $derived 派生状态用 `$derived` 符文声明: ¥Derived state is declared with the `$derived` rune: ```svelte

{count} doubled is {doubled}

``` `$derived(...)` 中的表达式应该没有副作用。Svelte 将禁止在派生表达式内更改状态(例如 `count++`)。 ¥The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions. 与 `$state` 一样,你可以将类字段标记为 `$derived`。 ¥As with `$state`, you can mark class fields as `$derived`. > > ¥[!NOTE] Code in Svelte components is only executed once at creation. Without the `$derived` rune, `doubled` would maintain its original value even when `count` changes. ## `$derived.by` 有时你需要创建不适合简短表达式的复杂派生。在这些情况下,你可以使用接受函数作为其参数的 `$derived.by`。 ¥Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument. ```svelte ``` 本质上,`$derived(expression)` 相当于 `$derived.by(() => expression)`。 ¥In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`. ## 了解依赖(Understanding dependencies) ¥Understanding dependencies 在 `$derived` 表达式(或 `$derived.by` 函数体)内同步读取的任何内容都被视为派生状态的依赖。当状态发生变化时,派生将被标记为脏,并在下次读取时重新计算。 ¥Anything read synchronously inside the `$derived` expression (or `$derived.by` function body) is considered a *dependency* of the derived state. When the state changes, the derived will be marked as *dirty* and recalculated when it is next read. 要使某个状态不被视为依赖,请使用 [`untrack`](svelte#untrack)。 ¥To exempt a piece of state from being treated as a dependency, use [`untrack`](svelte#untrack). ## 更新传播(Update propagation) ¥Update propagation Svelte 使用一种称为推拉反应性的东西 - 当状态更新时,依赖于状态的所有内容(无论是直接还是间接)都会立即收到更改通知('push'),但派生值不会重新评估,直到实际读取它们('pull')。 ¥Svelte uses something called *push-pull reactivity* — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the 'push'), but derived values are not re-evaluated until they are actually read (the 'pull'). 如果派生的新值在引用上与其先前的值相同,则将跳过下游更新。换句话说,Svelte 只会在 `large` 更改时更新按钮内的文本,而不会在 `count` 更改时更新,即使 `large` 依赖于 `count`: ¥If the new value of a derived is referentially identical to its previous value, downstream updates will be skipped. In other words, Svelte will only update the text inside the button when `large` changes, not when `count` changes, even though `large` depends on `count`: ```svelte ``` # $effect 效果是让你的应用执行操作的原因。当 Svelte 运行效果函数时,它会跟踪访问了哪些状态(和派生状态)(除非在 [`untrack`](svelte#untrack) 内部访问),并在该状态稍后发生变化时重新运行该函数。 ¥Effects are what make your application *do things*. When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. Svelte 应用中的大多数效果都是由 Svelte 本身创建的 - 例如,它们是当 `name` 更改时更新 `

hello {name}!

` 中的文本的位。 ¥Most of the effects in a Svelte app are created by Svelte itself — they're the bits that update the text in `

hello {name}!

` when `name` changes, for example. 但你也可以使用 `$effect` 符文创建自己的效果,这在你需要将外部系统(无论是库、`` 元素还是网络上的某些东西)与 Svelte 应用内部的状态同步时非常有用。 ¥But you can also create your own effects with the `$effect` rune, which is useful when you need to synchronize an external system (whether that's a library, or a `` element, or something across a network) with state inside your Svelte app. > > ¥[!NOTE] Avoid overusing `$effect`! When you do too much work in effects, code often becomes difficult to understand and maintain. See [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. 你的效果在组件安装到 DOM 后运行,并在状态更改([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=))后的 [microtask](https://web.nodejs.cn/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) 中运行: ¥Your effects run after the component has been mounted to the DOM, and in a [microtask](https://web.nodejs.cn/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): ```svelte ``` 重新运行是分批的(即在同一时刻更改 `color` 和 `size` 不会导致两次单独的运行),并且在应用任何 DOM 更新后发生。 ¥Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied. 你可以将 `$effect` 放置在任何地方,而不仅仅是组件的顶层,只要它在组件初始化期间调用(或在父效果处于活动状态时)。然后,它与组件(或父效果)的生命周期绑定在一起,因此当组件卸载(或父效果被销毁)时,它将自行销毁。 ¥You can place `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization (or while a parent effect is active). It is then tied to the lifecycle of the component (or parent effect) and will therefore destroy itself when the component unmounts (or the parent effect is destroyed). 你可以从 `$effect` 返回一个函数,该函数将在效果重新运行之前以及在被销毁之前立即运行([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=))。 ¥You can return a function from `$effect`, which will run immediately before the effect re-runs, and before it is destroyed ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=)). ```svelte

{count}

``` ### 了解依赖(Understanding dependencies) ¥Understanding dependencies `$effect` 会自动获取在其函数主体内同步读取的任何反应值(`$state`、`$derived`、`$props`)并将它们注册为依赖。当这些依赖发生变化时,`$effect` 会安排重新运行。 ¥`$effect` automatically picks up any reactive values (`$state`, `$derived`, `$props`) that are *synchronously* read inside its function body and registers them as dependencies. When those dependencies change, the `$effect` schedules a rerun. 异步读取的值(例如在 `await` 之后或在 `setTimeout` 内部)将不会被跟踪。在这里,当 `color` 更改时,画布将被重新绘制,但当 `size` 更改([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE31T246bMBD9lZF3pWSlBEirfaEQqdo_2PatVIpjBrDkGGQPJGnEv1e2IZfVal-wfHzmzJyZ4cIqqdCy9M-F0blDlnqArZjmB3f72XWRHVCRw_bc4me4aDWhJstSlllhZEfbQhekkMDKfwg5PFvihMvX5OXH_CJa1Zrb0-Kpqr5jkiwC48rieuDWQbqgZ6wqFLRcvkC-hYvnkWi1dWqa8ESQTxFRjfQWsOXiWzmr0sSLhEJu3p1YsoJkNUcdZUnN9dagrBu6FVRQHAM10sJRKgUG16bXcGxQ44AGdt7SDkTDdY02iqLHnJVU6hedlWuIp94JW6Tf8oBt_8GdTxlF0b4n0C35ZLBzXb3mmYn3ae6cOW74zj0YVzDNYXRHFt9mprNgHfZSl6mzml8CMoLvTV6wTZIUDEJv5us2iwMtiJRyAKG4tXnhl8O0yhbML0Wm-B7VNlSSSd31BG7z8oIZZ6dgIffAVY_5xdU9Qrz1Bnx8fCfwtZ7v8Qc9j3nB8PqgmMWlHIID6-bkVaPZwDySfWtKNGtquxQ23Qlsq2QJT0KIqb8dL0up6xQ2eIBkAg_c1FI_YqW0neLnFCqFpwmreedJYT7FVOBfwWRhXstZrSXiwKQjUhOZeMIleb5JZfHWn2Yq5pWEpmR7Hv-N_wEqT8hEEAAA=))时则不会: ¥Values that are read *asynchronously* — after an `await` or inside a `setTimeout`, for example — will not be tracked. Here, the canvas will be repainted when `color` changes, but not when `size` changes ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE31T246bMBD9lZF3pWSlBEirfaEQqdo_2PatVIpjBrDkGGQPJGnEv1e2IZfVal-wfHzmzJyZ4cIqqdCy9M-F0blDlnqArZjmB3f72XWRHVCRw_bc4me4aDWhJstSlllhZEfbQhekkMDKfwg5PFvihMvX5OXH_CJa1Zrb0-Kpqr5jkiwC48rieuDWQbqgZ6wqFLRcvkC-hYvnkWi1dWqa8ESQTxFRjfQWsOXiWzmr0sSLhEJu3p1YsoJkNUcdZUnN9dagrBu6FVRQHAM10sJRKgUG16bXcGxQ44AGdt7SDkTDdY02iqLHnJVU6hedlWuIp94JW6Tf8oBt_8GdTxlF0b4n0C35ZLBzXb3mmYn3ae6cOW74zj0YVzDNYXRHFt9mprNgHfZSl6mzml8CMoLvTV6wTZIUDEJv5us2iwMtiJRyAKG4tXnhl8O0yhbML0Wm-B7VNlSSSd31BG7z8oIZZ6dgIffAVY_5xdU9Qrz1Bnx8fCfwtZ7v8Qc9j3nB8PqgmMWlHIID6-bkVaPZwDySfWtKNGtquxQ23Qlsq2QJT0KIqb8dL0up6xQ2eIBkAg_c1FI_YqW0neLnFCqFpwmreedJYT7XX8FVOBfwWRhXstZrSXiwKQjUhOZeMIleb5JZfHWn2Yq5pWEpmR7Hv-N_wEqT8hEEAAA=)): ```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)。) ¥An effect only reruns when the object it reads changes, not when a property inside it changes. (If you want to observe changes *inside* an object at dev time, you can use [`$inspect`]($inspect).) ```svelte

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

``` 效果仅取决于它上次运行时读取的值。这对于具有条件代码的效果具有有趣的含义。 ¥An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code. 例如,如果下面代码片段中的 `a` 是 `true`,则 `if` 块内的代码将运行并评估 `b`。因此,更改为 `a` 或 `b` [将导致效果重新运行](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3VQzWrDMAx-FdUU4kBp71li6EPstOxge0ox8-QQK2PD-N1nLy2F0Z2Evj9_chKkP1B04pnYscc3cRCT8xhF95IEf8-Vq0DBr8rzPB_jJ3qumNERH-E2ECNxiRF9tIubWY00lgcYNAywj6wZJS8rtk83wjwgCrXHaULLUrYwKEgVGrnkx-Dx6MNFNstK5OjSbFGbwE0gdXuT_zGYrjmAuco515Hr1p_uXak3K3MgCGS9s-9D2grU-judlQYXIencnzad-tdR79qZrMyvw9wd5Z8Yv1h09dz8mn8AkM7Pfo0BAAA=)。 ¥For instance, if `a` is `true` in the code snippet below, the code inside the `if` block will run and `b` will be evaluated. As such, changes to either `a` or `b` [will cause the effect to re-run](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3VQzWrDMAx-FdUU4kBp71li6EPstOxge0ox8-QQK2PD-N1nLy2F0Z2Evj9_chKkP1B04pnYscc3cRCT8xhF95IEf8-Vq0DBr8rzPB_jJ3qumNERH-E2ECNxiRF9tIubWY00lgcYNAywj6wZJS8rtk83wjwgCrXHaULLUrYwKEgVGrnkx-Dx6MNFNstK5OjSbFGbwE0gdXuT_zGYrjmAuco515Hr1p_uXak3K3MgCGS9s-9D2grU-judlQYXIencnzad-tdR79qZrMyvw9wd5Z8Yv1h09dz8mn8AkM7Pfo0BAAA=). 相反,如果 `a` 是 `false`,则不会评估 `b`,并且只有当 `a` 更改时才会重新运行效果。 ¥Conversely, if `a` is `false`, `b` will not be evaluated, and the effect will *only* re-run when `a` changes. ```ts let a = false; let b = false; // ---cut--- $effect(() => { console.log('running'); if (a) { console.log('b:', b); } }); ``` ## `$effect.pre` 在极少数情况下,你可能需要在 DOM 更新之前运行代码。为此,我们可以使用 `$effect.pre` 符文: ¥In rare cases, you may need to run code *before* the DOM updates. For this we can use the `$effect.pre` rune: ```svelte
{#each messages as message}

{message}

{/each}
``` 除了时间之外,`$effect.pre` 的工作原理与 `$effect` 完全相同。 ¥Apart from the timing, `$effect.pre` works exactly like `$effect`. ## `$effect.tracking` `$effect.tracking` 符文是一项高级功能,可告诉你代码是否在跟踪上下文中运行,例如效果或模板内 ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACn3PwYrCMBDG8VeZDYIt2PYeY8Dn2HrIhqkU08nQjItS-u6buAt7UDzmz8ePyaKGMWBS-nNRcmdU-hHUTpGbyuvI3KZvDFLal0v4qvtIgiSZUSb5eWSxPfWSc4oB2xDP1XYk8HHiSHkICeXKeruDDQ4Demlldv4y0rmq6z10HQwuJMxGVv4mVVXDwcJS0jP9u3knynwtoKz1vifT_Z9Jhm0WBCcOTlDD8kyspmML5qNpHg40jc3fFryJ0iWsp_UHgz3180oBAAA=)): ¥The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACn3PwYrCMBDG8VeZDYIt2PYeY8Dn2HrIhqkU08nQjItS-u6buAt7UDzmz8ePyaKGMWBS-nNRcmdU-hHUTpGbyuvI3KZvDFLal0v4qvtIgiSZUSb5eWSxPfWSc4oB2xDP1XYk8HHiSHkICeXKeruDDQ4Demlldv4y0rmq6z10HQwuJMxGVv4mVVXDwcJS0jP9u3knynwtoKz1vifT_Z9Jhm0WBCcOTlDD8kyspmML5qNpHg40jc3fFryJ0iWsp_UHgz3180oBAAA=)): ```svelte

in template: {$effect.tracking()}

``` 它用于实现像 [`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber) 这样的抽象,它将创建监听器来更新反应值,但前提是这些值正在被跟踪(而不是例如在事件处理程序中读取)。 ¥It is used to implement abstractions like [`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber), which will create listeners to update reactive values but *only* if those values are being tracked (rather than, for example, read inside an event handler). ## `$effect.root` `$effect.root` 符文是一项高级功能,可创建不会自动清理的非跟踪范围。这对于你想要手动控制的嵌套效果很有用。此符文还允许在组件初始化阶段之外创建效果。 ¥The `$effect.root` rune is an advanced feature that creates a non-tracked scope that doesn't auto-cleanup. This is useful for nested effects that you want to manually control. This rune also allows for the creation of effects outside of the component initialisation phase. ```svelte ``` ## 何时不使用 `$effect`(When not to use `$effect`) ¥When not to use `$effect` 一般来说,`$effect` 最好被视为一种应急方案 - 对于分析和直接 DOM 操作等有用 - 而不是你应该经常使用的工具。特别是,避免使用它来同步状态。而不是这样... ¥In general, `$effect` is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state. Instead of this... ```svelte ``` ...执行以下操作: ¥...do this: ```svelte ``` > > ¥[!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`. 你可能想做一些复杂的效果来将一个值链接到另一个值。以下示例显示了 "多页应用" 和 "花费金额" 的两个相互连接的输入。如果你更新一个,另一个应该相应更新。不要为此([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACpVRy26DMBD8FcvKgUhtoIdeHBwp31F6MGSJkBbHwksEQvx77aWQqooq9bgzOzP7mGTdIHipPiZJowOpGJAv0po2VmfnDv4OSBErjYdneHWzBJaCjcx91TWOToUtCIEE3cig0OIty44r5l1oDtjOkyFIsv3GINQ_CNYyGegd1DVUlCR7oU9iilDUcP8S8roYs9n8p2wdYNVFm4csTx872BxNCcjr5I11fdgonEkXsjP2CoUUZWMv6m6wBz2x7yxaM-iJvWeRsvSbSVeUy5i0uf8vKA78NIeJLSZWv1I8jQjLdyK4XuTSeIdmVKJGGI4LdjVOiezwDu1yG74My8PLCQaSiroe5s_5C2PHrkVGAgAA))使用效果: ¥You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Don't use effects for this ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACpVRy26DMBD8FcvKgUhtoIdeHBwp31F6MGSJkBbHwksEQvx77aWQqooq9bgzOzP7mGTdIHipPiZJowOpGJAv0po2VmfnDv4OSBErjYdneHWzBJaCjcx91TWOToUtCIEE3cig0OIty44r5l1oDtjOkyFIsv3GINQ_CNYyGegd1DVUlCR7oU9iilDUcP8S8roYs9n8p2wdYNVFm4csTx872BxNCcjr5I11fdgonEkXsjP2CoUUZWMv6m6wBz2x7yxaM-iJvWeRsvSbSVeUy5i0uf8vKA78NIeJLSZWv1I8jQjLdyK4XuTSeIdmVKJGGI4LdjVOiezwDu1yG74My8PLCQaSiroe5s_5C2PHrkVGAgAA)): ```svelte ``` 相反,尽可能使用回调([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACo1SMW6EMBD8imWluFMSIEUaDiKlvy5lSOHjlhOSMRZeTiDkv8deMEEJRcqdmZ1ZjzzxqpZgePo5cRw18JQA_sSVaPz0rnVk7iDRYxdhYA8vW4Wg0NnwzJRdrfGtUAVKQIYtCsly9pIkp4AZ7cQOezAoEA7JcWUkVBuCdol0dNWrEutWsV5fHfnhPQ5wZJMnCwyejxCh6G6A0V3IHk4zu_jOxzzPBxBld83PTr7xXrb3rUNw8PbiYJ3FP22oTIoLSComq5XuXTeu8LzgnVA3KDgj13wiQ8taRaJ82rzXskYM-URRlsXktejjgNLoo9e4fyf70_8EnwncySX1GuunX6kGRwnzR_BgaPNaGy3FmLJKwrCUeBM6ZUn0Cs2mOlp3vwthQJ5i14P9st9vZqQlsQIAAA==)): ¥Instead, use callbacks where possible ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACo1SMW6EMBD8imWluFMSIEUaDiKlvy5lSOHjlhOSMRZeTiDkv8deMEEJRcqdmZ1ZjzzxqpZgePo5cRw18JQA_sSVaPz0rnVk7iDRYxdhYA8vW4Wg0NnwzJRdrfGtUAVKQIYtCsly9pIkp4AZ7cQOezAoEA7JcWUkVBuCdol0dNWrEutWsV5fHfnhPQ5wZJMnCwyejxCh6G6A0V3IHk4zu_jOxzzPBxBld83PTr7xXrb3rUNw8PbiYJ3FP22oTIoLSComq5XuXTeu8LzgnVA3KDgj13wiQ8taRaJ82rzXskYM-URRlsXktejjgNLoo9e4fyf70_8EnwncySX1GuunX6kGRwnzR_BgaPNaGy3FmLJKwrCUeBM6ZUn0Cs2mOlp3vwthQJ5i14P9st9vZqQlsQIAAA==)): ```svelte ``` 如果你出于某种原因需要使用绑定(例如当你想要某种“可写 `$derived`”时),请考虑使用 getter 和 setter 来同步状态([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACpWRwW6DMBBEf8WyekikFOihFwcq9TvqHkyyQUjGsfCCQMj_XnvBNKpy6Qn2DTOD1wu_tRocF18Lx9kCFwT4iRvVxenT2syNoDGyWjl4xi93g2AwxPDSXfrW4oc0EjUgwzsqzSr2VhTnxJwNHwf24lAhHIpjVDZNwy1KS5wlNoGMSg9wOCYksQccerMlv65p51X0p_Xpdt_4YEy9yTkmV3z4MJT579-bUqsaNB2kbI0dwlnCgirJe2UakJzVrbkKaqkWivasU1O1ULxnOVk3JU-Uxti0p_-vKO4no_enbQ_yXhnZn0aHs4b1jiJMK7q2zmo1C3bTMG3LaZQVrMjeoSPgaUtkDxePMCEX2Ie6b_8D4WyJJEwCAAA=)): ¥If you need to use bindings, for whatever reason (for example when you want some kind of "writable `$derived`"), consider using getters and setters to synchronise state ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACpWRwW6DMBBEf8WyekikFOihFwcq9TvqHkyyQUjGsfCCQMj_XnvBNKpy6Qn2DTOD1wu_tRocF18Lx9kCFwT4iRvVxenT2syNoDGyWjl4xi93g2AwxPDSXfrW4oc0EjUgwzsqzSr2VhTnxJwNHwf24lAhHIpjVDZNwy1KS5wlNoGMSg9wOCYksQccerMlv65p51X0p_Xpdt_4YEy9yTkmV3z4MJT579-bUqsaNB2kbI0dwlnCgirJe2UakJzVrbkKaqkWivasU1O1ULxnOVk3JU-Uxti0p_-vKO4no_enbQ_yXhnZn0aHs4b1jiJMK7q2zmo1C3bTMG3LaZQVrMjeoSPgaUtkDxePMCEX2Ie6b_8D4WyJJEwCAAA=)): ```svelte ``` 如果你绝对必须在效果内更新 `$state` 并因为你读取和写入相同的 `$state` 而陷入无限循环,请使用 [untrack](svelte#untrack)。 ¥If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack). # $props 组件的输入称为 props,是属性的缩写。你将 props 传递给组件就像你将属性传递给元素一样: ¥The inputs to a component are referred to as *props*, which is short for *properties*. You pass props to components just like you pass attributes to elements: ```svelte ``` 另一方面,在 `MyComponent.svelte` 内部,我们可以使用 `$props` 符文接收属性…… ¥On the other side, inside `MyComponent.svelte`, we can receive props with the `$props` rune... ```svelte

this component is {props.adjective}

``` ...但是更常见的是,你会 [destructure](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) 你的 props: ¥...though more commonly, you'll [*destructure*](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) your props: ```svelte

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

``` ## 后备值(Fallback values) ¥Fallback values 解构允许我们声明后备值,如果父组件未设置给定的 prop,则使用这些值: ¥Destructuring allows us to declare fallback values, which are used if the parent component does not set a given prop: ```js let { adjective = 'happy' } = $props(); ``` > > ¥[!NOTE] Fallback values are not turned into reactive state proxies (see [Updating props](#Updating-props) for more info) ## 重命名 props(Renaming props) ¥Renaming props 我们还可以使用解构赋值来重命名 props,如果它们是无效标识符或 JavaScript 关键字(如 `super`),则这是必需的: ¥We can also use the destructuring assignment to rename props, which is necessary if they're invalid identifiers, or a JavaScript keyword like `super`: ```js let { super: trouper = 'lights are gonna find me' } = $props(); ``` ## Rest 属性(Rest props) ¥Rest props 最后,我们可以使用 rest 属性来获取其余的 props: ¥Finally, we can use a *rest property* to get, well, the rest of the props: ```js let { a, b, c, ...others } = $props(); ``` ## 更新属性(Updating props) ¥Updating props 当 prop 本身更新时,对组件内部 prop 的引用也会更新 - 当 `count` 在 `App.svelte` 中更改时,它也会在 `Child.svelte` 中更改。但子组件能够暂时覆盖 prop 值,这对于未保存的短暂状态([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE6WQ0WrDMAxFf0WIQR0Wmu3VTQJln7HsIfVcZubIxlbGRvC_DzuBraN92qPula50tODZWB1RPi_IX16jLALWSOOUq6P3-_ihLWftNEZ9TVeOWBNHlNhGFYznfqCBzeRdYHh6M_YVzsFNsNs3pdpGd4eBcqPVDMrNxNDBXeSRtXioDgO1zU8ataeZ2RE4Utao924RFXQ9iHXwvoPHKpW1xY4g_Bg0cSVhKS0p560Za95612ZC02ONrD8ZJYdZp_rGQ37ff_mSP86Np2TWZaNNmdcH56P4P67K66_SXoK9pG-5dF5Z9QEAAA==))很有用: ¥References to a prop inside a component update when the prop itself updates — when `count` changes in `App.svelte`, it will also change inside `Child.svelte`. But the child component is able to temporarily override the prop value, which can be useful for unsaved ephemeral state ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE6WQ0WrDMAxFf0WIQR0Wmu3VTQJln7HsIfVcZubIxlbGRvC_DzuBraN92qPula50tODZWB1RPi_IX16jLALWSOOUq6P3-_ihLWftNEZ9TVeOWBNHlNhGFYznfqCBzeRdYHh6M_YVzsFNsNs3pdpGd4eBcqPVDMrNxNDBXeSRtXioDgO1zU8ataeZ2RE4Utao924RFXQ9iHXwvoPHKpW1xY4g_Bg0cSVhKS0p560Za95612ZC02ONrD8ZJYdZp_rGQ37ff_mSP86Np2TWZaNNmdcH56P4P67K66_SXoK9pG-5dF5Z9QEAAA==)): ```svelte ``` ```svelte ``` 虽然你可以暂时重新分配属性,但除非它们是 [bindable]($bindable),否则你不应该改变属性。 ¥While you can temporarily *reassign* props, you should not *mutate* props unless they are [bindable]($bindable). 如果 prop 是常规对象,则突变不会产生任何影响([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WQwU7DMBBEf2W1QmorQgJXk0RC3PkBwiExG9WQrC17U4Es_ztKUkQp9OjxzM7bjcjtSKjwyfKNp1aLORA4b13ADHszUED1HFE-3eyaBcy-Mw_O5eFAg8xa1wb6T9eWhVgCKiyD9sZJ3XAjZnTWCzzuzfAKvbcjbPJieR2jm_uGy-InweXqtd0baaliBG0nFgW3kBIUNWYo9CGoxE-UsgvIpw2_oc9-LmAPJBCPDJCggqvlVtvdH9puErEMlvVg9HsVtzuoaojzkKKAfRuALVDfk5ZZW0fmy05wXcFdwyktlUs-KIinljTXrRVnm7-kL9dYLVbUAQAA)): ¥If the prop is a regular object, the mutation will have no effect ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WQwU7DMBBEf2W1QmorQgJXk0RC3PkBwiExG9WQrC17U4Es_ztKUkQp9OjxzM7bjcjtSKjwyfKNp1aLORA4b13ADHszUED1HFE-3eyaBcy-Mw_O5eFAg8xa1wb6T9eWhVgCKiyD9sZJ3XAjZnTWCzzuzfAKvbcjbPJieR2jm_uGy-InweXqtd0baaliBG0nFgW3kBIUNWYo9CGoxE-UsgvIpw2_oc9-LmAPJBCPDJCggqvlVtvdH9puErEMlvVg9HsVtzuoaojzkKKAfRuALVDfk5ZZW0fmy05wXcFdwyktlUs-KIinljTXrRVnm7-kL9dYLVbUAQAA)): ```svelte ``` ```svelte ``` 但是,如果 prop 是反应状态代理,则突变会产生影响,但你会看到 [`ownership_invalid_mutation`](runtime-warnings#Client-warnings-ownership_invalid_mutation) 警告,因为组件正在改变不会 'belong' 的状态([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WR0U7DMAxFf8VESBuiauG1WycheOEbKA9p67FA6kSNszJV-XeUZhMw2GN8r-1znUmQ7FGU4pn2UqsOes-SlSGRia3S6ET5Mgk-2OiJBZGdOh6szd0eNcdaIx3-V28NMRI7UYq1awdleVNTzaq3ZmB43CndwXYwPSzyYn4dWxermqJRI4Np3rFlqODasWRcTtAaT1zCHYSbVU3r4nsyrdPMKTUFKDYiE4yfLEoePIbsQpqfy3_nOVMuJIqg0wk1RFg7GOuWfwEbz2wIDLVatR_VtLyBagNTHFIUMCqtoZXeIfAOU1JoUJsR2IC3nWTMjt7GM4yKdyBhlAMpesvhydCC0y_i0ZagHByMh26WzUhXUUxKnpbcVnBfUwhznJnNlac7JkuIURL-2VVfwxflyrWcSQIAAA==)): ¥If the prop is a reactive state proxy, however, then mutations *will* have an effect but you will see an [`ownership_invalid_mutation`](runtime-warnings#Client-warnings-ownership_invalid_mutation) warning, because the component is mutating state that does not 'belong' to it ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WR0U7DMAxFf8VESBuiauG1WycheOEbKA9p67FA6kSNszJV-XeUZhMw2GN8r-1znUmQ7FGU4pn2UqsOes-SlSGRia3S6ET5Mgk-2OiJBZGdOh6szd0eNcdaIx3-V28NMRI7UYq1awdleVNTzaq3ZmB43CndwXYwPSzyYn4dWxermqJRI4Np3rFlqODasWRcTtAaT1zCHYSbVU3r4nsyrdPMKTUFKDYiE4yfLEoePIbsQpqfy3_nOVMuJIqg0wk1RFg7GOuWfwEbz2wIDLVatR_VtLyBagNTHFIUMCqtoZXeIfAOU1JoUJsR2IC3nWTMjt7GM4yKdyBhlAMpesvhydCC0y_i0ZagHByMh26WzUhXUUxKnpbcVnBfUwhznJnNlac7JkuIURL-2VVfwxflyrWcSQIAAA==)): ```svelte ``` ```svelte ``` 未使用 `$bindable` 声明的 prop 的 fallback 值保持不变 — 它不会变成反应状态代理 — 这意味着突变不会导致更新([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WQwU7DMBBEf2VkIbUVoYFraCIh7vwA4eC4G9Wta1vxpgJZ_nfkBEQp9OjxzOzTRGHlkUQlXpy9G0gq1idCL43ppDrAD84HUYheGwqieo2CP3y2Z0EU3-En79fhRIaz1slA_-nKWSbLQVRiE9SgPTetbVkfvRsYzztttugHd8RiXU6vr-jisbWb8idhN7O3bEQhmN5ZVDyMlIorcOddv_Eufq4AGmJEuG5PilEjQrnRcoV7JCTUuJlGWq7-YHYjs7NwVhmtDnVcrlA3iLmzLLGTAdaB-j736h68Oxv-JM1I0AFjoG1OzPfX023c1nhobUoT39QeKsRzS8owM8DFTG_pE6dcVl70AQAA)) ¥The fallback value of a prop not declared with `$bindable` is left untouched — it is not turned into a reactive state proxy — meaning mutations will not cause updates ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WQwU7DMBBEf2VkIbUVoYFraCIh7vwA4eC4G9Wta1vxpgJZ_nfkBEQp9OjxzOzTRGHlkUQlXpy9G0gq1idCL43ppDrAD84HUYheGwqieo2CP3y2Z0EU3-En79fhRIaz1slA_-nKWSbLQVRiE9SgPTetbVkfvRsYzztttugHd8RiXU6vr-jisbWb8idhN7O3bEQhmN5ZVDyMlIorcOddv_Eufq4AGmJEuG5PilEjQrnRcoV7JCTUuJlGWq7-YHYjs7NwVhmtDnVcrlA3iLmzLLGTAdaB-j736h68Oxv-JM1I0AFjoG1OzPfX023c1nhobUoT39QeKsRzS8owM8DFTG_pE6dcVl70AQAA)) ```svelte ``` 总结:别担心,我知道我的意思使用回调 props 来传达更改,或者 - 如果父级和子级应该共享同一个对象 - 使用 [`$bindable`]($bindable) 符文。 ¥In summary: don't mutate props. Either use callback props to communicate changes, or — if parent and child should share the same object — use the [`$bindable`]($bindable) rune. ## 类型安全(Type safety) ¥Type safety 你可以通过注释你的 props 为你的组件添加类型安全性,就像你对任何其他变量声明所做的那样。在 TypeScript 中可能看起来像这样...... ¥You can add type safety to your components by annotating your props, as you would with any other variable declaration. In TypeScript that might look like this... ```svelte ``` ...而在 JSDoc 中你可以这样做: ¥...while in JSDoc you can do this: ```svelte ``` 当然,你可以将类型声明与注释分开: ¥You can, of course, separate the type declaration from the annotation: ```svelte ``` > > ¥[!NOTE] Interfaces for native DOM elements are provided in the `svelte/elements` module (see [Typing wrapper components](typescript#Typing-wrapper-components)) 建议添加类型,因为它可以确保使用组件的人可以轻松发现他们应该提供哪些属性。 ¥Adding types is recommended, as it ensures that people using your component can easily discover which props they should provide. # $bindable 通常,props 是单向的,从父级到子级。这使得你很容易理解数据在你的应用中是如何流动的。 ¥Ordinarily, props go one way, from parent to child. This makes it easy to understand how data flows around your app. 在 Svelte 中,组件 props 可以绑定,这意味着数据也可以从子级流到父级。这不是你应该经常做的事情,但如果谨慎使用,它可以简化你的代码。 ¥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'. 要将 prop 标记为可绑定,我们使用 `$bindable` 符文: ¥To mark a prop as bindable, we use the `$bindable` rune: ```svelte /// file: FancyInput.svelte ``` 现在,使用 `` 的组件可以添加 [`bind:`](bind) 指令([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WQwWrDMBBEf2URBSfg2nfFMZRCoYeecqx6UJx1IyqvhLUONcb_XqSkTUOSk1az7DBvJtEai0HI90nw6FHIJIhckO7i78n7IhzQctS2OuAtvXHESByEFFVoeuO5VqTYdN71DC-amvGV_MDQ9q6DrCjP0skkWymKJxYZOgxBfyKs4SGwZlxke7TWZcuVoqo8-1P1z3lraCcP2g64nk4GM5S1osrXf0JV-lrkgvGbheR-wDm_g30V8JL-1vpOCZFogpQsEsWcemtxscyhKArfOx9gjps0Lq4hzRVfemaYfu-PoIqqwKPFY_XpaIqj4tYRP7a6M3aUkD27zjSw0RTgbZN6Z8WNs66XsEP03tBXUueUJFlelvYx_wCuI3leNwIAAA==)): ¥Now, a component that uses `` can add the [`bind:`](bind) directive ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WQwWrDMBBEf2URBSfg2nfFMZRCoYeecqx6UJx1IyqvhLUONcb_XqSkTUOSk1az7DBvJtEai0HI90nw6FHIJIhckO7i78n7IhzQctS2OuAtvXHESByEFFVoeuO5VqTYdN71DC-amvGV_MDQ9q6DrCjP0skkWymKJxYZOgxBfyKs4SGwZlxke7TWZcuVoqo8-1P1z3lraCcP2g64nk4GM5S1osrXf0JV-lrkgvGbheR-wDm_g30V8JL-1vpOCZFogpQsEsWcemtxscyhKArfOx9gjps0Lq4hzRVfemaYfu-PoIqqwKPFY_XpaIqj4tYRP7a6M3aUkD27zjSw0RTgbZN6Z8WNs66XsEP03tBXUueUJFlelvYx_wCuI3leNwIAAA==)): ```svelte /// App.svelte

{message}

``` 父组件不必使用 `bind:` — 它只需传递普通 prop。有些父级不想听子级说些什么。 ¥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. 在这种情况下,你可以为根本没有传递任何 prop 的情况指定一个后备值: ¥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. `$inspect` 符文大致相当于 `console.log`,不同之处在于它会在其参数发生变化时重新运行。`$inspect` 深度跟踪反应状态,这意味着使用细粒度反应更新对象或数组内部的某些内容将导致其重新触发([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA)): ¥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](https://svelte.dev/playground/untitled#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA)): ```svelte ``` ## $inspect(...).with `$inspect` 返回一个属性 `with`,你可以使用回调来调用它,然后将调用回调而不是 `console.log`。回调的第一个参数是 `"init"` 或 `"update"`;后续参数是传递给 `$inspect` ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)) 的值: ¥`$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](https://svelte.dev/playground/untitled#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)): ```svelte ``` 查找某些更改的起源的一种方便方法是将 `console.trace` 传递给 `with`: ¥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(...) 此符文在 5.14 中添加,导致在开发中跟踪周围的函数。任何时候函数作为 [effect]($effect) 或 [derived]($derived) 的一部分重新运行时,都会将有关哪些反应状态导致效果触发的信息打印到控制台。 ¥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` 采用可选的第一个参数,该参数将用作标签。 ¥`$inspect.trace` takes an optional first argument which will be used as the label. # $host 将组件编译为自定义元素时,`$host` 符文提供对主机元素的访问,允许你(例如)分派自定义事件 ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)): ¥When compiling a component as a custom element, the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)): ```svelte /// file: Stepper.svelte ``` ```svelte /// file: App.svelte count -= 1} onincrement={() => count += 1} >

count: {count}

``` # 基本标记 Svelte 组件内的标记可以被视为 HTML++。 ¥Markup inside a Svelte component can be thought of as HTML++. ## 标签(Tags) ¥Tags 小写标签(如 `
`)表示常规 HTML 元素。大写标记或使用点符号的标记(例如 `` 或 ``)表示组件。 ¥A lowercase tag, like `
`, denotes a regular HTML element. A capitalised tag or a tag that uses dot notation, such as `` or ``, indicates a *component*. ```svelte
``` ## 元素属性(Element attributes) ¥Element attributes 默认情况下,属性的工作方式与其 HTML 对应项完全相同。 ¥By default, attributes work exactly like their HTML counterparts. ```svelte
``` 与 HTML 中一样,值可以不加引号。 ¥As in HTML, values may be unquoted. ```svelte ``` 属性值可以包含 JavaScript 表达式。 ¥Attribute values can contain JavaScript expressions. ```svelte page {p} ``` 或者它们可以是 JavaScript 表达式。 ¥Or they can *be* JavaScript expressions. ```svelte ``` 如果布尔属性的值为 [truthy](https://web.nodejs.cn/en-US/docs/Glossary/Truthy),则将其包含在元素中,如果值为 [falsy](https://web.nodejs.cn/en-US/docs/Glossary/Falsy),则将其排除。 ¥Boolean attributes are included on the element if their value is [truthy](https://web.nodejs.cn/en-US/docs/Glossary/Truthy) and excluded if it's [falsy](https://web.nodejs.cn/en-US/docs/Glossary/Falsy). 除非其他属性的值为 [nullish](https://web.nodejs.cn/en-US/docs/Glossary/Nullish)(`null` 或 `undefined`),否则将包含所有其他属性。 ¥All other attributes are included unless their value is [nullish](https://web.nodejs.cn/en-US/docs/Glossary/Nullish) (`null` or `undefined`). ```svelte
This div has no title attribute
``` > > ¥[!NOTE] Quoting a singular expression does not affect how the value is parsed, but in Svelte 6 it will cause the value to be coerced to a string: > > ```svelte > > ``` 当属性名称和值匹配(`name={name}`)时,可以将它们替换为 `{name}`。 ¥When the attribute name and value match (`name={name}`), they can be replaced with `{name}`. ```svelte ``` ## 组件属性(Component props) ¥Component props 按照惯例,传递给组件的值被称为属性或属性,而不是属性,这是 DOM 的一个功能。 ¥By convention, values passed to components are referred to as *properties* or *props* rather than *attributes*, which are a feature of the DOM. 与元素一样,`name={name}` 可以用 `{name}` 简写替换。 ¥As with elements, `name={name}` can be replaced with the `{name}` shorthand. ```svelte ``` 扩展属性允许将许多属性或属性一次传递到元素或组件。 ¥*Spread attributes* allow many attributes or properties to be passed to an element or component at once. 一个元素或组件可以具有多个散布属性,这些属性散布在常规属性中。 ¥An element or component can have multiple spread attributes, interspersed with regular ones. ```svelte ``` ## 事件(Events) ¥Events 通过向以 `on` 开头的元素添加属性,可以监听 DOM 事件。例如,要监听 `click` 事件,请将 `onclick` 属性添加到按钮: ¥Listening to DOM events is possible by adding attributes to the element that start with `on`. For example, to listen to the `click` event, add the `onclick` attribute to a button: ```svelte ``` 事件属性区分大小写。`onclick` 监听 `click` 事件,`onClick` 监听 `Click` 事件,这是不同的。这可确保你可以监听包含大写字符的自定义事件。 ¥Event attributes are case sensitive. `onclick` listens to the `click` event, `onClick` listens to the `Click` event, which is different. This ensures you can listen to custom events that have uppercase characters in them. 因为事件只是属性,所以适用与属性相同的规则: ¥Because events are just attributes, the same rules as for attributes apply: * 你可以使用简写形式:`` ¥you can use the shorthand form: `` * 你可以传播它们:`` ¥you can spread them: `` 从时间上讲,事件属性始终在绑定事件之后触发(例如,`oninput` 始终在更新到 `bind:value` 之后触发)。在底层,一些事件处理程序直接与 `addEventListener` 连接,而其他事件处理程序则是委托的。 ¥Timing-wise, event attributes always fire after events from bindings (e.g. `oninput` always fires after an update to `bind:value`). Under the hood, some event handlers are attached directly with `addEventListener`, while others are *delegated*. 使用 `ontouchstart` 和 `ontouchmove` 事件属性时,处理程序为 [passive](https://web.nodejs.cn/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners),以获得更好的性能。通过允许浏览器立即滚动文档,而不是等待查看事件处理程序是否调用 `event.preventDefault()`,这极大地提高了响应能力。 ¥When using `ontouchstart` and `ontouchmove` event attributes, the handlers are [passive](https://web.nodejs.cn/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) for better performance. This greatly improves responsiveness by allowing the browser to scroll the document immediately, rather than waiting to see if the event handler calls `event.preventDefault()`. 在极少数情况下,你需要防止这些事件默认值,你应该改用 [`on`](svelte-events#on)(例如在操作内部)。 ¥In the very rare cases that you need to prevent these event defaults, you should use [`on`](svelte-events#on) instead (for example inside an action). ### 事件委托(Event delegation) ¥Event delegation 为了减少内存占用并提高性能,Svelte 使用了一种称为事件委托的技术。这意味着对于某些事件(请参阅下面的列表),应用根目录中的单个事件监听器负责运行事件路径上的任何处理程序。 ¥To reduce memory footprint and increase performance, Svelte uses a technique called event delegation. This means that for certain events — see the list below — a single event listener at the application root takes responsibility for running any handlers on the event's path. 有几个需要注意的陷阱: ¥There are a few gotchas to be aware of: * 当你使用委托监听器手动分派事件时,请确保设置 `{ bubbles: true }` 选项,否则它将无法到达应用根 ¥when you manually dispatch an event with a delegated listener, make sure to set the `{ bubbles: true }` option or it won't reach the application root * 直接使用 `addEventListener` 时,避免调用 `stopPropagation`,否则事件将无法到达应用根,处理程序将不会被调用。类似地,在应用根目录内手动添加的处理程序将在 DOM 中声明性地添加的处理程序(例如 `onclick={...}`)之前运行,无论是在捕获阶段还是冒泡阶段。出于这些原因,最好使用从 `svelte/events` 而不是 `addEventListener` 导入的 `on` 函数,因为它将确保保留顺序并正确处理 `stopPropagation`。 ¥when using `addEventListener` directly, avoid calling `stopPropagation` or the event won't reach the application root and handlers won't be invoked. Similarly, handlers added manually inside the application root will run *before* handlers added declaratively deeper in the DOM (with e.g. `onclick={...}`), in both capturing and bubbling phases. For these reasons it's better to use the `on` function imported from `svelte/events` rather than `addEventListener`, as it will ensure that order is preserved and `stopPropagation` is handled correctly. 以下事件处理程序被委托: ¥The following event handlers are delegated: * `beforeinput` * `click` * `change` * `dblclick` * `contextmenu` * `focusin` * `focusout` * `input` * `keydown` * `keyup` * `mousedown` * `mousemove` * `mouseout` * `mouseover` * `mouseup` * `pointerdown` * `pointermove` * `pointerout` * `pointerover` * `pointerup` * `touchend` * `touchmove` * `touchstart` ## 文本表达式(Text expressions) ¥Text expressions JavaScript 表达式可以通过用大括号括起来作为文本包含在内。 ¥A JavaScript expression can be included as text by surrounding it with curly braces. ```svelte {expression} ``` 可以使用其 [HTML 实体](https://web.nodejs.cn/docs/Glossary/Entity) 字符串将大括号包含在 Svelte 模板中:`{` 为 `{`、`{` 或 `{`,`}` 为 `}`、`}` 或 `}`。 ¥Curly braces can be included in a Svelte template by using their [HTML entity](https://web.nodejs.cn/docs/Glossary/Entity) strings: `{`, `{`, or `{` for `{` and `}`, `}`, or `}` for `}`. 如果你使用的是正则表达式 (`RegExp`) [字面表示法](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#literal_notation_and_constructor),则需要将其括在括号中。 ¥If you're using a regular expression (`RegExp`) [literal notation](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#literal_notation_and_constructor), you'll need to wrap it in parentheses. ```svelte

Hello {name}!

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

{(/^[A-Za-z ]+$/).test(value) ? x : y}
``` 表达式将被字符串化并转义以防止代码注入。如果你想渲染 HTML,请改用 `{@html}` 标签。 ¥The expression will be stringified and escaped to prevent code injections. If you want to render HTML, use the `{@html}` tag instead. ```svelte {@html potentiallyUnsafeHtmlString} ``` > > ¥[!NOTE] Make sure that you either escape the passed string or only populate it with values that are under your control in order to prevent [XSS attacks](https://owasp.org/www-community/attacks/xss/) ## 注释(Comments) ¥Comments 你可以在组件内使用 HTML 注释。 ¥You can use HTML comments inside components. ```svelte

Hello world

``` 以 `svelte-ignore` 开头的注释将禁用下一个标记块的警告。通常,这些是可访问性警告;确保你出于充分的理由禁用它们。 ¥Comments beginning with `svelte-ignore` disable warnings for the next block of markup. Usually, these are accessibility warnings; make sure that you're disabling them for a good reason. ```svelte ``` 你可以添加以 `@component` 开头的特殊注释,当将鼠标悬停在其他文件中的组件名称上时会显示该注释。 ¥You can add a special comment starting with `@component` that will show up when hovering over the component name in other files. ` ```svelte

Hello, {name}

```` # {#if ...} ```svelte {#if expression}...{/if} ``` ```svelte {#if expression}...{:else if expression}...{/if} ``` ```svelte {#if expression}...{:else}...{/if} ``` 有条件渲染的内容可以封装在 if 块中。 ¥Content that is conditionally rendered can be wrapped in an if block. ```svelte {#if answer === 42}

what was the question?

{/if} ``` 可以使用 `{:else if expression}` 添加其他条件,可以选择以 `{:else}` 子句结尾。 ¥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} ``` 可以使用 each 块对值进行迭代。所讨论的值可以是数组、类似数组的对象(即具有 `length` 属性的任何内容)或可迭代对象(如 `Map` 和 `Set`) — 换句话说,任何可以与 `Array.from` 一起使用的内容。 ¥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}
``` 每个块还可以指定一个索引,相当于 `array.map(...)` 回调中的第二个参数: ¥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} ``` ## 为 each 块加键(Keyed each blocks) ¥Keyed each blocks ```svelte {#each expression as name (key)}...{/each} ``` ```svelte {#each expression as name, index (key)}...{/each} ``` 如果提供了键表达式(必须唯一地标识每个列表项),Svelte 将在数据更改时使用它来区分列表,而不是在末尾添加或删除项目。键可以是任何对象,但建议使用字符串和数字,因为它们允许在对象本身更改时保留身份。 ¥If a *key* expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. 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) ¥Each blocks without an item ```svelte {#each expression}...{/each} ``` ```svelte {#each expression, index}...{/each} ``` 如果你只想渲染 `n` 次,则可以省略 `as` 部分([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WR0W7CMAxFf8XKNAk0WsSeUEaRpn3Guoc0MbQiJFHiMlDVf18SOrZJ48259_jaVgZmxBEZZ28thgCNFV6xBdt1GgPj7wOji0t2EqI-wa_OleGEmpLWiID_6dIaQkMxhm1UdwKpRQhVzWSaVORJNdvWpqbhAYVsYQCNZk8thzWMC_DCHMZk3wPSThNQ088I3mghD9UwSwHwlLE5PMIzVFUFq3G7WUZ2OyUvU3JOuZU332wCXTRmtPy1NgzXZtUFp8WFw9536uWqpbIgPEaDsJBW90cTOHh0KGi2XsBq5-cT6-3nPauxXqHnsHJnCFZ3CvJVkyuCQ0mFF9TZyCQ162WGvteLKfG197Y3iv_pz_fmS68Hxt8iPBPj5HscP8YvCNX7uhYCAAA=)): ¥In case you just want to render something `n` times, you can omit the `as` part ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WR0W7CMAxFf8XKNAk0WsSeUEaRpn3Guoc0MbQiJFHiMlDVf18SOrZJ48259_jaVgZmxBEZZ28thgCNFV6xBdt1GgPj7wOji0t2EqI-wa_OleGEmpLWiID_6dIaQkMxhm1UdwKpRQhVzWSaVORJNdvWpqbhAYVsYQCNZk8thzWMC_DCHMZk3wPSThNQ088I3mghD9UwSwHwlLE5PMIzVFUFq3G7WUZ2OyUvU3JOuZU332wCXTRmtPy1NgzXZtUFp8WFw9536uWqpbIgPEaDsJBW90cTOHh0KGi2XsBq5-cT6-3nPauxXqHnsHJnCFZ3CvJVkyuCQ0mFF9TZyCQ162WGvteLKfG197Y3iv_pz_fmS68Hxt8iPBPj5HscP8YvCNX7uhYCAAA=)): ```svelte
    {#each { length: 8 }, rank} {#each { length: 8 }, file}
    {/each} {/each}
    ``` ## else 块(Else blocks) ¥Else blocks ```svelte {#each expression as name}...{:else}...{/each} ``` 每个块还可以有一个 `{:else}` 子句,如果列表为空,则会渲染该子句。 ¥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 块允许你在 [`Promise`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) 的三种可能状态上进行分支 - 待处理、已完成或已拒绝。 ¥Await blocks allow you to branch on the three possible states of a [`Promise`](https://web.nodejs.cn/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} ``` > > ¥[!NOTE] During server-side rendering, only the pending branch will be rendered. > > 如果提供的表达式不是 `Promise`,则只会渲染 `:then` 分支,包括在服务器端渲染期间。 > > ¥If the provided expression is not a `Promise`, only the `:then` branch will be rendered, including during server-side rendering. 如果在 promise 拒绝(或不可能出现错误)时不需要渲染任何内容,则可以省略 `catch` 块。 ¥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} ``` 类似地,如果你只想显示错误状态,则可以省略 `then` 块。 ¥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} ``` > > ¥[!NOTE] You can use `#await` with [`import(...)`](https://web.nodejs.cn/en-US/docs/Web/JavaScript/Reference/Operators/import) to render components lazily: ```svelte > {#await import('./Component.svelte') then { default: Component }} > > {/await} > ``` # {#snippet ...} ```svelte {#snippet name()}...{/snippet} ``` ```svelte {#snippet name(param1, param2, paramN)}...{/snippet} ``` Snippet 和 [渲染标签](@render) 是一种在组件内部创建可重用标记块的方法。不再需要像 [this](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=) 那样编写重复的代码... ¥Snippets, and [render tags](@render), are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=)... ```svelte {#each images as image} {#if image.href}
    {image.caption}
    {image.caption}
    {:else}
    {image.caption}
    {image.caption}
    {/if} {/each} ``` ...你可以写 [this](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE5VUYW-bMBD9KxbRlERKY4jWfSA02n5H6QcXDmwVbMs-lnaI_z6D7TTt1moTAnPvzvfenQ_GpBEd2CS_HxPJekjy5IfWyS7BFz0b9id0CM62ajDVjBS2MkLjqZQldoBE9KwFS-7I_YyUOPqlRGuqnKw5orY5pVpUduj3mitUln5LU3pI0_UuBp9FjTwnDr9AHETLMSeHK6xiGoWSLi9yYT034cwSRjohn17zcQPNFTs8s153sK9Uv_Yh0-5_5d7-o9zbD-UqCaRWrllSYZQxLw_HUhb0ta-y4NnJUxfUvc7QuLJSaO0a3oh2MLBZat8u-wsPnXzKQvTtVVF34xK5d69ThFmHEQ4SpzeVRediTG8rjD5vBSeN3E5JyHh6R1DQK9-iml5kjzQUN_lSgVU8DhYLx7wwjSvRkMDvTjiwF4zM1kXZ7DlF1eN3A7IG85e-zRrYEjjm0FkI4Cc7Ripm0pHOChexhcWXzreeZyRMU6Mk3ljxC9w4QH-cQZ_b3T5pjHxk1VNr1CDrnJy5QDh6XLO6FrLNSRb2l9gz0wo3S6m7HErSgLsPGMHkpDZK31jOanXeHPQz-eruLHUP0z6yTbpbrn223V70uMXNSpQSZjpL0y8hcxxpNqA6_ql3BQAxlxvfpQ_uT9GrWjQC6iRHM8D0MP0GQsIi92QEAAA=): ¥...you can write [this](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE5VUYW-bMBD9KxbRlERKY4jWfSA02n5H6QcXDmwVbMs-lnaI_z6D7TTt1moTAnPvzvfenQ_GpBEd2CS_HxPJekjy5IfWyS7BFz0b9id0CM62ajDVjBS2MkLjqZQldoBE9KwFS-7I_YyUOPqlRGuqnKw5orY5pVpUduj3mitUln5LU3pI0_UuBp9FjTwnDr9AHETLMSeHK6xiGoWSLi9yYT034cwSRjohn17zcQPNFTs8s153sK9Uv_Yh0-5_5d7-o9zbD-UqCaRWrllSYZQxLw_HUhb0ta-y4NnJUxfUvc7QuLJSaO0a3oh2MLBZat8u-wsPnXzKQvTtVVF34xK5d69ThFmHEQ4SpzeVRediTG8rjD5vBSeN3E5JyHh6R1DQK9-iml5kjzQUN_lSgVU8DhYLx7wwjSvRkMDvTjiwF4zM1kXZ7DlF1eN3A7IG85e-zRrYEjjm0FkI4Cc7Ripm0pHOChexhcWXzreeZyRMU6Mk3ljxC9w4QH-cQZ_b3T5pjHxk1VNr1CDrnJy5QDh6XLO6FrLNSRb2l9gz0wo3S6m7HErSgLsPGMHkpDZK31jOanXeHPQz-eruLHUP0z6yTbpbrn223V70uMXNSpQSZjpL0y8hcxxpNqA6_ql3BQAxlxvfpQ_uT9GrWjQC6iRHM8D0MP0GQsIi92QEAAA=): ```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} ``` 与函数声明一样,代码片段可以有任意数量的参数,这些参数可以有默认值,并且你可以解构每个参数。但是,你不能使用 rest 参数。 ¥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) ¥Snippet scope Snippet 可以在组件内部的任何位置声明。它们可以引用在自身之外声明的值,例如在 ` {#snippet hello(name)}

    hello {name}! {message}!

    {/snippet} {@render hello('alice')} {@render hello('bob')} ``` ...并且它们对于同一词汇范围内的所有内容都是 'visible'(即兄弟姐妹和这些兄弟姐妹的子项): ¥...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()} ``` Snippet 可以引用自身和彼此 ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE2WPTQqDMBCFrxLiRqH1Zysi7TlqF1YnENBJSGJLCYGeo5tesUeosfYH3c2bee_jjaWMd6BpfrAU6x5oTvdS0g01V-mFPkNnYNRaDKrxGxto5FKCIaeu1kYwFkauwsoUWtZYPh_3W5FMY4U2mb3egL9kIwY0rbhgiO-sDTgjSEqSTvIDs-jiOP7i_MHuFGAL6p9BtiSbOTl0GtzCuihqE87cqtyam6WRGz_vRcsZh5bmRg3gju4Fptq_kzQBAAA=)): ¥Snippets can reference themselves and each other ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE2WPTQqDMBCFrxLiRqH1Zysi7TlqF1YnENBJSGJLCYGeo5tesUeosfYH3c2bee_jjaWMd6BpfrAU6x5oTvdS0g01V-mFPkNnYNRaDKrxGxto5FKCIaeu1kYwFkauwsoUWtZYPh_3W5FMY4U2mb3egL9kIwY0rbhgiO-sDTgjSEqSTvIDs-jiOP7i_MHuFGAL6p9BtiSbOTl0GtzCuihqE87cqtyam6WRGz_vRcsZh5bmRg3gju4Fptq_kzQBAAA=)): ```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) ¥Passing snippets to components 在模板中,片段与其他片段一样都是值。因此,它们可以传递作为 props ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3VS247aMBD9lZGpBGwDASRegonaPvQL2qdlH5zYEKvBNvbQLbL875VzAcKyj3PmzJnLGU8UOwqSkd8KJdaCk4TsZS0cyV49wYuJuQiQpGd-N2bu_ooaI1YwJ57hpVYoFDqSEepKKw3mO7VDeTTaIvxiRS1gb_URxvO0ibrS8WanIrHUyiHs7Vmigy28RmyHHmKvDMbMmFq4cQInvGSwTsBYWYoMVhCSB2rBFFPsyl0uruTlR3JZCWvlTXl1Yy_mawiR_rbZKZrellJ-5JQ0RiBUgnFhJ9OGR7HKmwVoilXeIye8DOJGfYCgRlZ3iE876TBsZPX7hPdteO75PC4QaIo8vwNPePmANQ2fMeEFHrLD7rR1jTNkW986E8C3KwfwVr8HSHOSEBT_kGRozyIkn_zQveXDL3rIfPJHtUDwzShJd_Qk3gQCbOGLsdq4yfTRJopRuin3I7nv6kL7ARRjmLdBDG3uv1mhuLA3V2mKtqNEf_oCn8p9aN-WYqH5peP4kWBl1UwJzAEPT9U7K--0fRrrWnPTXpCm1_EVdXjpNmlA8G1hPPyM1fKgMqjFHjctXGjLhZ05w0qpDhksGrybuNEHtJnCalZWsuaTlfq6nPaaBSv_HKw-K57BjzOiVj9ZKQYKzQjZodYFqydYTRN4gPhVzTDO2xnma3HsVWjaLjT8nbfwHy7Q5f2dBAAA)) 传递给组件: ¥Within the template, snippets are values just like any other. As such, they can be passed to components as props ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3VS247aMBD9lZGpBGwDASRegonaPvQL2qdlH5zYEKvBNvbQLbL875VzAcKyj3PmzJnLGU8UOwqSkd8KJdaCk4TsZS0cyV49wYuJuQiQpGd-N2bu_ooaI1YwJ57hpVYoFDqSEepKKw3mO7VDeTTaIvxiRS1gb_URxvO0ibrS8WanIrHUyiHs7Vmigy28RmyHHmKvDMbMmFq4cQInvGSwTsBYWYoMVhCSB2rBFFPsyl0uruTlR3JZCWvlTXl1Yy_mawiR_rbZKZrellJ-5JQ0RiBUgnFhJ9OGR7HKmwVoilXeIye8DOJGfYCgRlZ3iE876TBsZPX7hPdteO75PC4QaIo8vwNPePmANQ2fMeEFHrLD7rR1jTNkW986E8C3KwfwVr8HSHOSEBT_kGRozyIkn_zQveXDL3rIfPJHtUDwzShJd_Qk3gQCbOGLsdq4yfTRJopRuin3I7nv6kL7ARRjmLdBDG3uv1mhuLA3V2mKtqNEf_oCn8p9aN-WYqH5peP4kWBl1UwJzAEPT9U7K--0fRrrWnPTXpCm1_EVdXjpNmlA8G1hPPyM1fKgMqjFHjctXGjLhZ05w0qpDhksGrybuNEHtJnCalZWsuaTlfq6nPaaBSv_HKw-K57BjzOiVj9ZKQYKzQjZodYFqydYTRN4gPhVzTDO2xnma3HsVWjaLjT8nbfwHy7Q5f2dBAAA)): ```svelte {#snippet header()} fruit qty price total {/snippet} {#snippet row(d)} {d.name} {d.qty} {d.price} {d.qty * d.price} {/snippet} ``` 可以将其想象为将内容而不是数据传递给组件。这个概念类似于 Web 组件中的插槽。 ¥Think about it like passing content instead of data to a component. The concept is similar to slots in web components. 为了方便创作,直接在组件内部声明的代码片段会隐式成为组件([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3VSTa_aMBD8Kyu_SkAbCA-JSzBR20N_QXt6vIMTO8SqsY29tI2s_PcqTiB8vaPHs7MzuxuIZgdBMvJLo0QlOElIJZXwJHsLBBvb_XUASc7Mb9Yu_B-hsMMK5sUzvDQahUZPMkJ96aTFfKd3KA_WOISfrFACKmcOMFmk8TWUTjY73RFLoz1C5U4SPWzhrcN2GKDrlcGEWauEnyRwxCaDdQLWyVJksII2uaMWTDPNLtzX5YX8-kgua-GcHJVXI3u5WEPb0d83O03TMZSmfRzOkG1Db7mNacOL19JagVALxoWbztq-H8U6j0SaYp2P2BGbOyQ2v8PQIFMXLKRDk177pq0zf6d8bMrzwBdd0pamyPMb-IjNEzS2f86Gz_Dwf-2F9nvNSUJQ_EOSoTuJNvngqK5v4Pas7n4-OCwlEEJcQTIMO-nSQwtb-GSdsX46e9gbRoP9yGQ11I0rEuycunu6PHx1QnPhxm3SFN15MOlYEFJZtf0dUywMbwZOeBGsrKNLYB54-1R9WNqVdki7usim6VmQphf7mnpshiQRhNAXdoOfMyX3OgMlKtz0cGEcF27uLSul3mewjPjgOOoDukxjPS9rqfh0pb-8zs6aBSt_7505aZ7B9xOi0T9YKW4UooVsr0zB1BTrWQJ3EL-oWcZ572GxFoezCk37QLe3897-B2i2U62uBAAA))上的 props: ¥As an authoring convenience, snippets declared directly *inside* a component implicitly become props *on* the component ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3VSTa_aMBD8Kyu_SkAbCA-JSzBR20N_QXt6vIMTO8SqsY29tI2s_PcqTiB8vaPHs7MzuxuIZgdBMvJLo0QlOElIJZXwJHsLBBvb_XUASc7Mb9Yu_B-hsMMK5sUzvDQahUZPMkJ96aTFfKd3KA_WOISfrFACKmcOMFmk8TWUTjY73RFLoz1C5U4SPWzhrcN2GKDrlcGEWauEnyRwxCaDdQLWyVJksII2uaMWTDPNLtzX5YX8-kgua-GcHJVXI3u5WEPb0d83O03TMZSmfRzOkG1Db7mNacOL19JagVALxoWbztq-H8U6j0SaYp2P2BGbOyQ2v8PQIFMXLKRDk177pq0zf6d8bMrzwBdd0pamyPMb-IjNEzS2f86Gz_Dwf-2F9nvNSUJQ_EOSoTuJNvngqK5v4Pas7n4-OCwlEEJcQTIMO-nSQwtb-GSdsX46e9gbRoP9yGQ11I0rEuycunu6PHx1QnPhxm3SFN15MOlYEFJZtf0dUywMbwZOeBGsrKNLYB54-1R9WNqVdki7usim6VmQphf7mnpshiQRhNAXdoOfMyX3OgMlKtz0cGEcF27uLSul3mewjPjgOOoDukxjPS9rqfh0pb-8zs6aBSt_7505aZ7B9xOi0T9YKW4UooVsr0zB1BTrWQJ3EL-oWcZ572GxFoezCk37QLe3897-B2i2U62uBAAA)): ```svelte
    {#snippet header()} {/snippet} {#snippet row(d)} {/snippet}
    fruit qty price total{d.name} {d.qty} {d.price} {d.qty * d.price}
    ``` 组件内任何不属于声明片段的内容都将成为特殊的 `children` 片段。 ¥Any content inside the component tags that is *not* a snippet declaration implicitly becomes part of the `children` snippet ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE3WOQQrCMBBFrzIMggql3ddY1Du4si5sOmIwnYRkFKX07lKqglqX8_7_w2uRDw1hjlsWI5ZqTPBoLEXMdy3K3fdZDzB5Ndfep_FKVnpWHSKNce1YiCVijirqYLwUJQOYxrsgsLmIOIZjcA1M02w4n-PpomSVvTclqyEutDX6DA2pZ7_ABIVugrmEC3XJH92P55_G39GodCmWBFrQJ2PrQAwdLGHig_NxNv9xrQa1dhWIawrv1Wzeqawa8953D-8QOmaEAQAA)): ```svelte ``` ```svelte ``` > > ¥[!NOTE] Note that you cannot have a prop called `children` if you also have content inside the component — for this reason, you should avoid having props with that name 你可以将代码片段属性声明为可选。如果未设置代码片段,你可以使用可选链接不渲染任何内容... ¥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?.()} ``` ...或使用 `#if` 块来渲染后备内容: ¥...or use an `#if` block to render fallback content: ```svelte {#if children} {@render children()} {:else} fallback content {/if} ``` ## 键入片段(Typing snippets) ¥Typing snippets Snippet 实现从 `'svelte'` 导入的 `Snippet` 接口: ¥Snippets implement the `Snippet` interface imported from `'svelte'`: ```svelte ``` 进行此更改后,如果你尝试在不提供 `data` prop 和 `row` 代码片段的情况下使用该组件,则会出现红色波浪线。请注意,提供给 `Snippet` 的类型参数是一个元组,因为代码片段可以有多个参数。 ¥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. 我们可以通过声明泛型来进一步收紧,以便 `data` 和 `row` 引用相同的类型: ¥We can tighten things up further by declaring a generic, so that `data` and `row` refer to the same type: ```svelte ``` ## 导出代码片段(Exporting snippets) ¥Exporting snippets 在 `.svelte` 文件顶层声明的 Snippet 可以从 ` {#snippet add(a, b)} {a} + {b} = {a + b} {/snippet} ``` > > ¥[!NOTE] > This requires Svelte 5.5.0 or newer ## 程序化代码片段(Programmatic snippets) ¥Programmatic snippets 可以使用 [`createRawSnippet`](svelte#createRawSnippet) API 以编程方式创建 Snippet。这适用于高级用例。 ¥Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases. ## 代码片段和插槽(Snippets and slots) ¥Snippets and slots 在 Svelte 4 中,可以使用 [slots](legacy-slots) 将内容传递给组件。Snippet 功能更强大、更灵活,因此在 Svelte 5 中已弃用插槽。 ¥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 ...} 要渲染 [snippet](snippet),请使用 `{@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)} ``` 表达式可以是像 `sum` 这样的标识符,也可以是任意的 JavaScript 表达式: ¥The expression can be an identifier like `sum`, or an arbitrary JavaScript expression: ```svelte {@render (cool ? coolSnippet : lameSnippet)()} ``` ## 可选片段(Optional snippets) ¥Optional snippets 如果代码片段可能未定义(例如,因为它是一个传入的 prop),那么你可以使用可选链接仅在定义时渲染它: ¥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?.()} ``` 或者,使用带有 `:else` 子句的 [`{#if ...}`](if) 块来渲染后备内容: ¥Alternatively, use an [`{#if ...}`](if) block with an `:else` clause to render fallback content: ```svelte {#if children} {@render children()} {:else}

    fallback content

    {/if} ``` # {@html ...} 要将原始 HTML 注入组件,请使用 `{@html ...}` 标记: ¥To inject raw HTML into your component, use the `{@html ...}` tag: ```svelte
    {@html content}
    ``` > > ¥[!NOTE] Make sure that you either escape the passed string or only populate it with values that are under your control in order to prevent [XSS attacks](https://owasp.org/www-community/attacks/xss/). Never render unsanitized content. 表达式应该是有效的独立 HTML — 这不起作用,因为 `
    ` 不是有效的 HTML: ¥The expression should be valid standalone HTML — this will not work, because `
    ` is not valid HTML: ```svelte {@html '
    '}content{@html '
    '} ``` 它也不会编译 Svelte 代码。 ¥It also will not compile Svelte code. ## 样式(Styling) ¥Styling 以这种方式渲染的内容对 Svelte 来说是 'invisible',因此不会接收 [作用域样式](scoped-styles) — 换句话说,这将不起作用,并且 `a` 和 `img` 样式将被视为未使用: ¥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}
    ``` 相反,使用 `:global` 修饰符来定位 `
    ` 内的所有内容: ¥Instead, use the `:global` modifier to target everything inside the `
    `: ```svelte ``` # {@const ...} `{@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}` 仅允许作为块(`{#if ...}`、`{#each ...}`、`{#snippet ...}` 等)或 `` 的直接子项。 ¥`{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — or a ``. # {@debug ...} `{@debug ...}` 标签提供了 `console.log(...)` 的替代方案。当特定变量的值发生变化时,它会记录它们,并在打开开发工具时暂停代码执行。 ¥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 ...}` 接受以逗号分隔的变量名列表(不是任意表达式)。 ¥`{@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'} ``` 没有任何参数的 `{@debug}` 标签将插入一个 `debugger` 语句,该语句在任何状态发生变化时触发,而不是指定的变量。 ¥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: 数据通常从父级向下流动到子级。`bind:` 指令允许数据以另一种方式流动,从子级流向父级。 ¥Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent. 一般语法是 `bind:property={expression}`,其中 `expression` 是左值(即变量或对象属性)。当表达式是与属性同名的标识符时,我们可以省略表达式 - 换句话说,它们是等效的: ¥The general syntax is `bind:property={expression}`, where `expression` is an *lvalue* (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 创建一个更新绑定值的事件监听器。如果元素已经具有同一事件的监听器,则将在更新绑定值之前触发该监听器。 ¥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) ¥Function bindings 你还可以使用 `bind:property={get, set}`,其中 `get` 和 `set` 是函数,允许你执行验证和转换: ¥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()} /> ``` 在像 [尺寸绑定](#Dimensions) 这样的只读绑定的情况下,`get` 值应该是 `null`: ¥In the case of readonly bindings like [dimension bindings](#Dimensions), the `get` value should be `null`: ```svelte
    ...
    ``` > > ¥[!NOTE] > Function bindings are available in Svelte 5.9.0 and newer. ## `` `` 元素上的 `bind:value` 指令绑定输入的 `value` 属性: ¥A `bind:value` directive on an `` element binds the input's `value` property: ```svelte

    {message}

    ``` 在数字输入(`type="number"` 或 `type="range"`)的情况下,该值将被强制转换为数字([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE6WPwYoCMQxAfyWEPeyiOOqx2w74Hds9pBql0IllmhGXYf5dKqwiyILsLXnwwsuI-5i4oPkaUX8yo7kCnKNQV7dNzoty4qSVBSr8jG-Poixa0KAt2z5mbb14TaxA4OCtKCm_rz4-f2m403WltrlrYhMFTtcLNkoeFGqZ8yhDF7j3CCHKzpwoDexGmqCL4jwuPUJHZ-dxVcfmyYGe5MAv-La5pbxYFf5Z9Zf_UJXb-sEMquFgJJhBmGyTW5yj8lnRaD_w9D1dAKSSj7zqAQAA)): ¥In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number ([demo](https://svelte.dev/playground/untitled#H4sIAAAAAAAAE6WPwYoCMQxAfyWEPeyiOOqx2w74Hds9pBql0IllmhGXYf5dKqwiyILsLXnwwsuI-5i4oPkaUX8yo7kCnKNQV7dNzoty4qSVBSr8jG-Poixa0KAt2z5mbb14TaxA4OCtKCm_rz4-f2m403WltrlrYhMFTtcLNkoeFGqZ8yhDF7j3CCHKzpwoDexGmqCL4jwuPUJHZ-dxVcfmyYGe5MAv-La5pbxYFf5Z9Zf_UJXb-sEMquFgJJhBmGyTW5yj8lnRaD_w9D1dAKSSj7zqAQAA)): ```svelte

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

    ``` 如果输入为空或无效(在 `type="number"` 的情况下),则值为 `undefined`。 ¥If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`. 自 5.6.0 起,如果 `` 具有 `defaultValue` 并且是表单的一部分,则在重置表单时它将恢复为该值而不是空字符串。请注意,对于初始渲染,除非绑定的值是 `null` 或 `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
    ``` > > ¥[!NOTE] > Use reset buttons sparingly, and ensure that users won't accidentally click them while trying to submit the form. ## `` 复选框和单选输入可以与 `bind:checked` 绑定: ¥Checkbox and radio inputs can be bound with `bind:checked`: ```svelte ``` 自 5.6.0 起,如果 `` 具有 `defaultChecked` 属性并且是表单的一部分,则在重置表单时它将恢复为该值而不是 `false`。请注意,对于初始渲染,除非绑定的值是 `null` 或 `undefined`,否则绑定的值优先。 ¥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
    ``` ## `` 一起工作的输入可以使用 `bind:group`。 ¥Inputs that work together can use `bind:group`. ```svelte ``` > > ¥[!NOTE] `bind:group` only works if the inputs are in the same Svelte component. ## `` 在具有 `type="file"` 的 `` 元素上,你可以使用 `bind:files` 来获取 [所选文件的 `FileList` 个](https://web.nodejs.cn/en-US/docs/Web/API/FileList)。当你想要以编程方式更新文件时,你始终需要使用 `FileList` 对象。目前无法直接构造 `FileList` 对象,因此你需要创建一个新的 [`DataTransfer`](https://web.nodejs.cn/en-US/docs/Web/API/DataTransfer) 对象并从那里获取 `files`。 ¥On `` elements with `type="file"`, you can use `bind:files` to get the [`FileList` of selected files](https://web.nodejs.cn/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://web.nodejs.cn/en-US/docs/Web/API/DataTransfer) object and get `files` from there. ```svelte ``` `FileList` 对象也无法修改,因此如果你想从列表中删除单个文件,则需要创建一个新的 `DataTransfer` 对象并添加要保留的文件。 ¥`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. > > ¥[!NOTE] `DataTransfer` may not be available in server-side JS runtimes. Leaving the state that is bound to `files` uninitialized prevents potential errors if components are server-side rendered. ## `` 值绑定对应于所选 ` ``` `` element behaves similarly to a checkbox group. The bound variable is an array with an entry corresponding to the `value` property of each selected `