首页 / Svelte 5 入门教程 / 组件 Props $props

Svelte 5 入门教程

组件 Props $props

本教程共 50 篇 · 第 10 篇 · 更新于 2026-08-05 · 约 5 分钟阅读

SvelteSvelte 5Runes$props组件

10. 组件 Props $props

本节目标:掌握 $props() 的各种用法,包括解构、默认值、rest props、展开和 children。学完你能灵活地在组件间传递数据。

基本用法

父组件向子组件传值,就像给 HTML 元素加属性一样:

<!--- file: App.svelte --->
<script>
	import MyComponent from './MyComponent.svelte';
</script>

<MyComponent adjective="很酷" />

子组件用 $props() 接收:

<!--- file: MyComponent.svelte --->
<script>
	let { adjective } = $props();
</script>

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

也可以不解构,直接用 props.属性名 访问:

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

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

不过解构写法更简洁,实际开发中更常用。

默认值

如果父组件没传某个 prop,可以用解构默认值兜底:

<script>
	// 没传 adjective 时,默认值为 '开心'
	let { adjective = '开心' } = $props();
</script>

<p>这个组件{adjective}</p>
<!-- 父组件不传 adjective -->
<MyComponent />
<!-- 输出:这个组件开心 -->

<!-- 父组件传了 adjective -->
<MyComponent adjective="强大" />
<!-- 输出:这个组件强大 -->
Note

默认值只有在 prop 未传入或值为 undefined 时才生效。传入 null 或空字符串不会触发默认值。

重命名 props

如果 prop 名是 JavaScript 保留字(如 super),或不是合法标识符,可以用重命名语法:

<script>
	// 把 super prop 重命名为 trouper
	let { super: trouper = 'lights are gonna find me' } = $props();
</script>

<p>{trouper}</p>

Rest props:收集剩余属性

... 收集未解构的剩余 props:

<!--- file: Button.svelte --->
<script>
	// a 和 b 被单独解构,其余的都进 others
	let { a, b, ...others } = $props();
</script>

<p>a={a}, b={b}</p>
<p>其他属性: {JSON.stringify(others)}</p>
<!-- 父组件 -->
<Button a="1" b="2" c="3" d="4" />
<!-- 输出: a=1, b=2 / 其他属性: {"c":"3","d":"4"} -->
Tip

rest props 在封装「透传所有属性」的组件时特别有用,比如给 <input> 加一层封装,把所有原生属性透传过去。

Props 展开

父组件可以用 {...对象} 展开批量传 props:

<script>
	import Button from './Button.svelte';

	let config = {
		type: 'submit',
		disabled: false,
		label: '提交'
	};
</script>

<!-- 展开 config 的所有属性作为 props -->
<Button {...config} />

展开可以和普通 props 混用,顺序决定优先级——后面的覆盖前面的:

<!-- config.label 会覆盖 label="默认" -->
<!-- size="lg" 会覆盖 config.size(如果有)-->
<Button label="默认" {...config} size="lg" />

children:保留字

每个组件都可以接收一个特殊的 prop:children。它代表组件标签之间的内容:

<!--- file: Card.svelte --->
<script>
	let { children } = $props();
</script>

<div class="card">
	{@render children()}
</div>

<style>
	.card {
		border: 1px solid #ddd;
		border-radius: 8px;
		padding: 16px;
	}
</style>
<!-- 父组件 -->
<Card>
	<h2>标题</h2>
	<p>这是卡片内容。</p>
</Card>

children 是一个 snippet(代码片段),需要用 {@render children()} 来渲染。关于 snippet 的详细用法,后面有专门一章讲。

Note

Svelte 4 用 <slot> 来渲染子内容,Svelte 5 改用 children + {@render}。新写法更灵活,可以传递参数。

Props 的响应性

props 是响应式的——父组件更新 prop 时,子组件会自动更新:

<!--- file: App.svelte --->
<script>
	import Child from './Child.svelte';
	let count = $state(0);
</script>

<button onclick={() => count++}>父组件:{count}</button>
<Child {count} />
<!--- file: Child.svelte --->
<script>
	let { count } = $props();
</script>

<p>子组件收到:{count}</p>

子组件可以临时重新赋值 prop,但这只是本地覆盖,不会影响父组件:

<!--- file: Child.svelte --->
<script>
	let { count } = $props();
</script>

<!-- 点击只改变子组件的 count,父组件不变 -->
<button onclick={() => count++}>
	子组件:{count}
</button>
Warning

不要直接修改 props 的属性(prop.count++),除非它声明为 $bindable。直接修改不属于你的状态会导致警告。

TypeScript 类型标注

给 props 加上类型,方便调用方知道该传什么:

<script lang="ts">
	interface Props {
		title: string;
		count?: number;       // 可选属性
		items: string[];
	}

	let { title, count = 0, items }: Props = $props();
</script>

也可以用内联类型:

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

推荐用 interface Props 的写法,清晰且可复用。如果组件暴露 snippet props(如 children),需要用 Snippet 类型标注,后面 snippet 章节会讲。

$props.id():唯一 ID

$props.id() 生成当前组件实例的唯一 ID,在 SSR 时服务端和客户端保持一致:

<script>
	const uid = $props.id();
</script>

<form>
	<label for="{uid}-name">姓名:</label>
	<input id="{uid}-name" type="text" />
</form>

适合用在 foraria-labelledby 等需要关联元素的场景。

本节回顾

  • $props() 接收组件属性,解构写法最常用
  • 解构默认值在 prop 未传入或为 undefined 时生效
  • { super: trouper } 可以重命名 prop
  • { ...rest } 收集剩余属性,适合透传场景
  • {...对象} 展开批量传 props,后覆盖前
  • children 是保留 prop,用 {@render children()} 渲染
  • props 可临时重新赋值但不建议修改属性,需要双向同步用 $bindable
  • TypeScript 用 interface Props 标注类型
  • $props.id() 生成 SSR 一致的唯一 ID