$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:
<script>
import MyComponent from './MyComponent.svelte';
</script>
<MyComponent adjective="cool" />
<script lang="ts">
import MyComponent from './MyComponent.svelte';
</script>
<MyComponent adjective="cool" />
另一方面,在 MyComponent.svelte
内部,我们可以使用 $props
符文接收属性……
¥On the other side, inside MyComponent.svelte
, we can receive props with the $props
rune...
<script>
let props = $props();
</script>
<p>this component is {props.adjective}</p>
<script lang="ts">
let props = $props();
</script>
<p>this component is {props.adjective}</p>
...但是更常见的是,你会 destructure 你的 props:
¥...though more commonly, you’ll destructure your props:
<script>
let { adjective } = $props();
</script>
<p>this component is {adjective}</p>
<script lang="ts">
let { adjective } = $props();
</script>
<p>this component is {adjective}</p>
后备值(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:
let { let adjective: any
adjective = 'happy' } = function $props(): any
Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
$props();
后备值不会变成反应状态代理(有关更多信息,请参阅 更新属性)
¥[!NOTE] Fallback values are not turned into reactive state proxies (see 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
:
let { super: let trouper: any
trouper = 'lights are gonna find me' } = function $props(): any
Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
$props();
Rest 属性(Rest props)
¥Rest props
最后,我们可以使用 rest 属性来获取其余的 props:
¥Finally, we can use a rest property to get, well, the rest of the props:
let { let a: any
a, let b: any
b, let c: any
c, ...let others: any
others } = function $props(): any
Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
$props();
更新属性(Updating props)
¥Updating props
当 prop 本身更新时,对组件内部 prop 的引用也会更新 - 当 count
在 App.svelte
中更改时,它也会在 Child.svelte
中更改。但子组件能够暂时覆盖 prop 值,这对于未保存的短暂状态(demo)很有用:
¥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):
<script>
import Child from './Child.svelte';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />
<script lang="ts">
import Child from './Child.svelte';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />
<script>
let { count } = $props();
</script>
<button onclick={() => (count += 1)}>
clicks (child): {count}
</button>
<script lang="ts">
let { count } = $props();
</script>
<button onclick={() => (count += 1)}>
clicks (child): {count}
</button>
虽然你可以暂时重新分配属性,但除非它们是 bindable,否则你不应该改变属性。
¥While you can temporarily reassign props, you should not mutate props unless they are bindable.
如果 prop 是常规对象,则突变不会产生任何影响(demo):
¥If the prop is a regular object, the mutation will have no effect (demo):
<script>
import Child from './Child.svelte';
</script>
<Child object={{ count: 0 }} />
<script lang="ts">
import Child from './Child.svelte';
</script>
<Child object={{ count: 0 }} />
<script>
let { object } = $props();
</script>
<button onclick={() => {
// has no effect
object.count += 1
}}>
clicks: {object.count}
</button>
<script lang="ts">
let { object } = $props();
</script>
<button onclick={() => {
// has no effect
object.count += 1
}}>
clicks: {object.count}
</button>
但是,如果 prop 是反应状态代理,则突变会产生影响,但你会看到 ownership_invalid_mutation
警告,因为组件正在改变不会 ‘belong’ 的状态(demo):
¥If the prop is a reactive state proxy, however, then mutations will have an effect but you will see an ownership_invalid_mutation
warning, because the component is mutating state that does not ‘belong’ to it (demo):
<script>
import Child from './Child.svelte';
let object = $state({count: 0});
</script>
<Child {object} />
<script lang="ts">
import Child from './Child.svelte';
let object = $state({count: 0});
</script>
<Child {object} />
<script>
let { object } = $props();
</script>
<button onclick={() => {
// will cause the count below to update,
// but with a warning. Don't mutate
// objects you don't own!
object.count += 1
}}>
clicks: {object.count}
</button>
<script lang="ts">
let { object } = $props();
</script>
<button onclick={() => {
// will cause the count below to update,
// but with a warning. Don't mutate
// objects you don't own!
object.count += 1
}}>
clicks: {object.count}
</button>
未使用 $bindable
声明的 prop 的 fallback 值保持不变 — 它不会变成反应状态代理 — 这意味着突变不会导致更新(demo)
¥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)
<script>
let { object = { count: 0 } } = $props();
</script>
<button onclick={() => {
// has no effect if the fallback value is used
object.count += 1
}}>
clicks: {object.count}
</button>
<script lang="ts">
let { object = { count: 0 } } = $props();
</script>
<button onclick={() => {
// has no effect if the fallback value is used
object.count += 1
}}>
clicks: {object.count}
</button>
总结:别担心,我知道我的意思使用回调 props 来传达更改,或者 - 如果父级和子级应该共享同一个对象 - 使用 $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
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...
<script lang="ts">
let { adjective }: { adjective: string } = $props();
</script>
...而在 JSDoc 中你可以这样做:
¥...while in JSDoc you can do this:
<script>
/** @type {{ adjective: string }} */
let { adjective } = $props();
</script>
当然,你可以将类型声明与注释分开:
¥You can, of course, separate the type declaration from the annotation:
<script lang="ts">
interface Props {
adjective: string;
}
let { adjective }: Props = $props();
</script>
svelte/elements
模块中提供了原生 DOM 元素的接口(参见 键入封装器组件)¥[!NOTE] Interfaces for native DOM elements are provided in the
svelte/elements
module (see Typing wrapper components)
建议添加类型,因为它可以确保使用组件的人可以轻松发现他们应该提供哪些属性。
¥Adding types is recommended, as it ensures that people using your component can easily discover which props they should provide.