Skip to main content

$props

组件的输入称为 props,这是 properties 的缩写。你将 props 传递给组件,就像将属性传递给元素一样:

App
<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 符文接收 props...

MyComponent
<script>
	let props = $props();
</script>

<p>这个组件是 {props.adjective}</p>
<script lang="ts">
	let props = $props();
</script>

<p>这个组件是 {props.adjective}</p>

...更常见的是,你会 解构 你的 props:

MyComponent
<script>
	let { adjective } = $props();
</script>

<p>这个组件是 {adjective}</p>
<script lang="ts">
	let { adjective } = $props();
</script>

<p>这个组件是 {adjective}</p>

后备值(Fallback values)

解构允许我们声明后备值,如果父组件没有设置给定的 prop,就会使用这些后备值:

let { let adjective: anyadjective = '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();

https://svelte.dev/docs/svelte/$props

$props
();

后备值不会变成响应式状态代理(有关更多信息,请参见更新 props

重命名 props

我们也可以用解构赋值来重命名 props,如果它们是无效标识符,或者是像 super 这样的 JavaScript 关键字,这样做是必要的:

let { super: let trouper: anytrouper = '光芒终会照亮我' } = function $props(): any

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();

https://svelte.dev/docs/svelte/$props

$props
();

剩余 props

最后,我们可以使用 剩余属性 来获取,其实就是获取剩下的 props:

let { let a: anya, let b: anyb, let c: anyc, ...let others: anyothers } = function $props(): any

Declares the props that a component accepts. Example:

let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();

https://svelte.dev/docs/svelte/$props

$props
();

更新 props

当 prop 本身更新时,组件内部对该 prop 的引用也会更新——当 countApp.svelte 中发生变化时,它在 Child.svelte 内部也会相应改变。但是子组件能暂时覆盖 prop 的值,这对未保存的临时状态很有用(demo):

App
<script>
	import Child from './Child.svelte';

	let count = $state(0);
</script>

<button onclick={() => (count += 1)}>
	点击次数(父组件):{count}
</button>

<Child {count} />
<script lang="ts">
	import Child from './Child.svelte';

	let count = $state(0);
</script>

<button onclick={() => (count += 1)}>
	点击次数(父组件):{count}
</button>

<Child {count} />
Child
<script>
	let { count } = $props();
</script>

<button onclick={() => (count += 1)}>
	点击次数(子组件):{count}
</button>
<script lang="ts">
	let { count } = $props();
</script>

<button onclick={() => (count += 1)}>
	点击次数(子组件):{count}
</button>

虽然你可以临时 重新赋值 props,但除非它们是 可绑定 的 props,否则不应 修改 props。

如果 prop 是一个普通对象,修改将没有效果(demo):

App
<script>
	import Child from './Child.svelte';
</script>

<Child object={{ count: 0 }} />
<script lang="ts">
	import Child from './Child.svelte';
</script>

<Child object={{ count: 0 }} />
Child
<script>
	let { object } = $props();
</script>

<button onclick={() => {
	// 没有效果
	object.count += 1
}}>
	点击次数:{object.count}
</button>
<script lang="ts">
	let { object } = $props();
</script>

<button onclick={() => {
	// 没有效果
	object.count += 1
}}>
	点击次数:{object.count}
</button>

如果 prop 是一个响应式状态代理,那么修改它会产生效果,但你会看到一个 ownership_invalid_mutation 警告,因为该组件正在修改不“属于”它的状态(demo):

App
<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} />
Child
<script>
	let { object } = $props();
</script>

<button onclick={() => {
	// 会导致下面的 count 更新,
	// 但会有警告。不要修改
	// 你不拥有的对象!
	object.count += 1
}}>
	点击次数:{object.count}
</button>
<script lang="ts">
	let { object } = $props();
</script>

<button onclick={() => {
	// 会导致下面的 count 更新,
	// 但会有警告。不要修改
	// 你不拥有的对象!
	object.count += 1
}}>
	点击次数:{object.count}
</button>

未使用 $bindable 声明的 prop 的后备值将保持不变——它不会被转换为响应式状态代理——这意味着对其的修改不会触发更新(demo):

Child
<script>
	let { object = { count: 0 } } = $props();
</script>

<button onclick={() => {
	// 如果使用默认值,是没有效果的
	object.count += 1
}}>
	点击次数:{object.count}
</button>
<script lang="ts">
	let { object = { count: 0 } } = $props();
</script>

<button onclick={() => {
	// 如果使用默认值,是没有效果的
	object.count += 1
}}>
	点击次数:{object.count}
</button>

总之:不要修改 props。要么使用回调 props 来传递变化,要么——如果父子组件应该共享同一个对象——使用 $bindable 符文。

类型安全

通过对 props 进行注解,你可以为组件添加类型安全,就像对其他变量声明一样。在 TypeScript 中,它看起来是这样的...

<script lang="ts">
	let { adjective }: { adjective: string } = $props();
</script>

...而在 JSDoc 中你可以这样做:

<script>
	/** @type {{ adjective: string }} */
	let { adjective } = $props();
</script>

当然,你也可以将类型声明与注解分开:

<script lang="ts">
	interface Props {
		adjective: string;
	}

	let { adjective }: Props = $props();
</script>

建议添加类型,这样可以确保使用你组件的人可以轻松发现他们应该提供哪些 props。

在 GitHub 编辑此页面

上一页 下一页