组件 Props $props
本教程共 50 篇 · 第 10 篇 · 更新于 2026-08-05 · 约 5 分钟阅读
本节目标:掌握 $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"} -->
Tiprest 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 的详细用法,后面有专门一章讲。
NoteSvelte 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>
适合用在 for 和 aria-labelledby 等需要关联元素的场景。
本节回顾
$props()接收组件属性,解构写法最常用- 解构默认值在 prop 未传入或为
undefined时生效 { super: trouper }可以重命名 prop{ ...rest }收集剩余属性,适合透传场景{...对象}展开批量传 props,后覆盖前children是保留 prop,用{@render children()}渲染- props 可临时重新赋值但不建议修改属性,需要双向同步用
$bindable - TypeScript 用
interface Props标注类型 $props.id()生成 SSR 一致的唯一 ID