Appearance
props — 父传子的"快递通道"
props 是父组件向子组件传递数据的机制,单向:父传子,子不能直接改。
父组件(有数据)
│
│ props(单向)
↓
子组件(接收数据,用在自己的模板里)
最简单的例子
父组件:
vue
<template>
<Child title="来自父组件的数据" />
</template>
<script>
import Child from './Child.vue'
export default {
components: { Child }
}
</script>
子组件(Child.vue):
vue
<template>
<p>父组件说的是:{{ title }}</p>
</template>
<script>
export default {
props: ['title']
}
</script>
动态绑定 — 传变量而不是固定值
传变量时加冒号:
vue
<Child :title="parentMsg" />
| 写法 | 传给子组件的 |
|---|---|
title="hello" | 字符串 "hello" |
:title="hello" | 变量 hello 的值 |
:title="'hello'" | 字符串 "hello"(表达式) |
加了冒号,等号后面的是 JavaScript 表达式,不是字符串。
单向数据流
props 是单向的,子不能直接改父传过来的值:
javascript
// ❌ 错误
this.title = '新标题' // 会导致 Vue 报错
子组件确实需要改时:
- 把 prop 赋给本地 data(子组件内部自己用)
- 通过事件通知父组件改
传递多种数据类型
规则:传非字符串类型必须加冒号 :。
数字
vue
<Child :age="25" /> <!-- ✅ 传数字 -->
<Child age="25" /> <!-- ❌ 传字符串 "25" -->
数组
vue
<Child :names="['张三', '李四', '王五']" />
对象
vue
<Child :user="userInfo" />
布尔值
vue
<Child :is-admin="true" />
Props 校验
给 prop 加上类型、必填、默认值等规则,让组件更健壮。
从简单到完整
javascript
// 第 1 级:只声明名字
props: ['title']
// 第 2 级:指定类型
props: {
title: String
}
// 第 3 级:加更多规则
props: {
title: {
type: String,
required: true,
default: '默认标题'
}
}
完整示例
javascript
props: {
title: {
type: String,
required: true
},
age: {
type: Number,
default: 18
},
tags: {
type: Array,
default() { // ⚠️ 对象/数组必须用函数返回
return []
}
},
status: {
type: String,
validator(value) {
return ['active', 'inactive'].includes(value)
}
}
}
| 选项 | 作用 |
|---|---|
type | 期望的类型:String, Number, Boolean, Array, Object, Date, Function |
required | 是否必传 |
default | 默认值(对象/数组必须用函数返回) |
validator | 自定义校验函数,返回 true 通过 |
支持多种类型
javascript
width: {
type: [Number, String],
default: 100
}
类型校验
当 prop 类型不对时,控制台会打印 warning(不是 error,页面仍能运行):
[Vue warn]: Invalid prop: type check failed for prop "age".
Expected Number, got String with value "25".
💡 Tip:type 校验只在开发环境生效,不影响生产性能。
新手常见问题
Q:我的 prop 传了但子组件拿不到?
- 子组件有没有在
props里声明 - 父组件传的时候有没有写冒号
- prop 名字拼写是否一致
Q:prop 名字在父模板里怎么写?
- 父模板用小写横杠:
my-title - 子组件 JS 用驼峰:
myTitle
Q:为什么对象/数组的 default 必须是函数?
- 确保每个组件实例拿到的是独立副本,而不是共享同一个引用