Props 是 Vue 中父组件向子组件传递数据的核心机制,用于实现父子组件之间的单向数据流,保证应用状态的可预测性。
Props 是组件的自定义属性,通过标签属性的形式为子组件传值
Props 是只读的,子组件禁止直接修改,严格遵循单向数据流规范
我们在原有输入框组件的基础上,新增标签文本、占位提示、最大输入长度等 Props,让组件更灵活复用。
修改文件 src/components/MyText/src/index.vue,集成 Props 定义、模板使用,兼容原有功能且符合最新语法:
<template>
<!-- 使用 Props 渲染标签文本 -->
<label class="my-label" for="text-input">{{ label }}:</label>
<!-- 绑定 Props 与原生属性,保留双向绑定能力 -->
<input
id="text-input"
type="text"
class="my-input-text"
:value="modelValue"
@input="$emit('update:modelValue', ($event.target as HTMLInputElement)?.value ?? '')"
:placeholder="placeholder"
:maxlength="maxLength"
/>
</template>
<script setup lang="ts">
// defineProps 是编译时宏,无需手动导入
// 1. 对象写法:支持类型校验、必填、默认值
const props = defineProps({
// 标签文本:字符串类型,必填项
label: {
type: String,
required: true,
},
// 占位提示:字符串类型,非必填,带默认值
placeholder: {
type: String,
default: '请输入内容',
},
// 最大输入长度:数字类型,非必填
maxLength: {
type: Number,
default: 20,
},
// 双向绑定值:继承原有功能
modelValue: {
type: String,
default: '',
},
})
// 定义事件,配合 v-model 使用
const emit = defineEmits(['update:modelValue'])
</script>
<style scoped>
/* 中英文与数字之间添加空格 */
.my-label {
margin-right: 8px;
font-size: 14px;
color: #333;
}
.my-input-text {
width: 80%;
padding: 10px;
border-radius: 3px;
border: 1px solid #ccc;
outline: none;
}
.my-input-text:focus {
border-color: #409eff;
}
</style>沿用之前的 src/components/MyText/index.ts,保持组件导出规范不变:
// 导入组件核心文件
import MyText from './src/index.vue'
// 具名导出(用于局部注册)
export { MyText }
// 默认导出(支持 app.use 全局注册)
export default {
install(app: any) {
app.component('MyText', MyText)
}
}在业务组件中使用 MyText,通过简写语法传递 Props,支持静态值和动态值两种方式:
<template>
<div class="demo-container">
<h3>Props 传值演示</h3>
<!-- 1. 静态传值:直接传递字符串 -->
<MyText label="用户名" placeholder="请输入账号" />
<!-- 2. 动态传值:绑定响应式数据 -->
<MyText :label="userLabel" :max-length="10" v-model="value" />
</div>
</template>
<script setup lang="ts">
// 导入组件
import { MyText } from './components/MyText'
import { ref } from 'vue'
// 动态 Props 数据
const userLabel = ref('密码')
const value = ref('')
</script>
<style scoped>
.demo-container {
padding: 20px;
}
</style>defineProps 是 Vue 3 <script setup> 专属的编译时宏,无需导入、无需调用,专门用于声明组件 Props,支持两种配置方式:
简易写法(仅指定类型)
const props = defineProps(['label', 'placeholder'])完整写法(推荐,支持校验、必填、默认值)
const props = defineProps({
label: {
type: String, // 数据类型
required: true, // 是否必填
default: '标题', // 默认值
}
})type 支持所有 JS 基础类型与引用类型:
基础类型:String、Number、Boolean、Symbol
引用类型:Object、Array、Function
静态传值:直接传递固定字符串
<MyText label="用户名" />动态传值:使用 :(v-bind 简写)绑定变量 / 表达式
<MyText :label="dynamicLabel" :max-length="10" />在 TS 项目中,推荐使用泛型写法定义 Props,类型校验更严格、代码更简洁:
<script setup lang="ts">
// TS 泛型 + withDefaults 定义默认值(Vue 3 最新语法)
interface Props {
label: string
placeholder?: string
maxLength?: number
modelValue?: string
}
// 声明 Props 并配置默认值
const props = withDefaults(defineProps<Props>(), {
placeholder: '请输入内容',
maxLength: 20,
modelValue: '',
})
</script>Props 是只读的 子组件不能直接修改 Props 的值,Vue 会抛出警告,避免数据混乱:
// ❌ 错误写法
props.label = '新标题'单向数据流
数据只能从 父组件 → 子组件 单向传递,保证数据流向唯一、易于调试。
修改方案
子组件需要修改数据时,通过 emit 触发事件,由父组件修改原值。
Prop 命名规范
子组件使用小驼峰(maxLength),模板中使用短横线分隔(max-length),Vue 会自动转换。
必填 Prop 校验
如果设置 required: true,父组件未传值时,控制台会抛出警告,提升开发健壮性。
属性透传
未定义的原生属性(如 class、id)会自动绑定到组件根元素,无需额外声明。
Props 是父子组件传值的核心,遵循单向数据流、只读不可改原则
defineProps 是 Vue 3 声明 Props 的标准方式,支持校验与默认值
TS 泛型写法是企业级开发的最佳实践,类型安全更可靠
静态传值直接书写,动态传值必须使用 : 简写语法