组件通信:Props 与 Emit

发布时间:2026/8/10 20:28:28
组件通信:Props 与 Emit 第7课 组件通信Props 与 Emit能将页面拆分为独立的组件并组合使用掌握Props实现父组件向子组件传递数据类型校验、默认值掌握Emit实现子组件向父组件通信自定义事件传参理解单向数据流与“数据在谁手里逻辑就在谁那里”的设计原则1. 组件的基础使用组件就是一个独立的.vue文件自带 template、script、style 三件套。使用组件需要三步步骤操作写法创建新建.vue文件src/components/AppHeader.vue注册在父组件中import引入import AppHeader from ./components/AppHeader.vue使用在父组件模板中像标签一样写AppHeader /在script setup中import即自动注册无需额外代码。2. 父传子PropsProps是父组件传递给子组件的“数据包裹”子组件通过defineProps声明自己需要接收哪些数据。2.1 子组件声明接收script setup // AppHeader.vue const props defineProps({ title: { type: String, // 类型校验 default: 后台管理系统 // 默认值父组件没传时使用 }, userInfo: { type: Object, default: () ({ name: 游客, role: 访客 }) // 对象/数组默认值必须用函数返回 } }) /script声明后模板中直接使用 props 名称无需.value{{ title }}、{{ userInfo.name }}。2.2 父组件传值!-- 静态传值不带冒号直接传字符串 -- AppHeader title静态标题 / !-- 动态传值带冒号将变量的值传过去 -- AppHeader :user-infouserInfo /关键动态传值必须加冒号:否则右边会被当作字符串字面量如userInfo这个字符串而不是变量值。2.3 命名规则驼峰 vs 短横线子组件声明时使用camelCase驼峰userInfo父组件传递时使用kebab-case短横线:user-info模板中使用时使用camelCase{{ userInfo }}Vue 会自动进行转换单单词无需变化如title。2.4 单向数据流Props 是只读的子组件不能直接修改接收到的 props否则控制台会警告target is readonly。如果需要改变应通过emit 通知父组件修改或由父组件重新传入新值。2.5 类型校验与默认值type可指定String、Number、Boolean、Array、Object等传错时控制台会亮警告不影响运行。default基本类型直接写值对象/数组必须写成函数每次返回新对象副本避免多个组件实例共享同一份数据。3. 子传父Emit (自定义事件)子组件可以通过emit向父组件“按门铃”——通知父组件发生了什么事并可携带参数。3.1 子组件声明与触发script setup // AppMenu.vue const emit defineEmits([select-menu]) // 声明事件 function handleClick(menu) { emit(select-menu, menu) // 触发事件并将 menu 对象作为参数传出 } /script3.2 父组件监听与处理template AppMenu select-menuhandleSelectMenu / /template script setup function handleSelectMenu(menu) { // menu 就是子组件传过来的参数 activeMenu.value menu.name } /script事件带参emit(事件名, 参数)的第二个参数即载荷父组件监听函数直接以参数形式接收。3.3 事件命名建议使用动词开头或短横线连接logout、select-menu三处命名必须完全一致defineEmits([...])、emit(...)、...这是最常见的坑。4. 组件通信模式总结方向机制写法关键词父 → 子Props子defineProps父:属性数据子 → 父Emit子defineEmitsemit(事件)父事件函数核心原则“数据在谁手里逻辑就在谁那里”。父组件持有数据和业务逻辑子组件只负责展现和上报事件。5. 组件命名与拆分规范命名规范组件文件名PascalCase多单词如AppHeader.vue避免与原生标签冲突。自定义事件动词开头、短横线分隔如select-menu。应用级组件建议加统一前缀如App方便识别。何时拆分组件三个信号同一段代码在多个地方重复出现如多个页面共用同一个头部单个文件过长滚动寻代码费劲某块区域的数据和逻辑自成一体与其它部分无关6. 常见问题排查表现象可能原因解决办法组件不显示import路径错误、文件名大小写不对、模板中未使用标签核对路径、文件名确认标签已写在模板中子组件接收不到数据父组件未传值、动态传值忘加冒号、属性名不一致驼峰/短横线检查:user-info与userInfo对应确保已传控制台类型校验警告传入的值类型与defineProps声明不符按警告提示修正类型例如应传对象却传了数字子组件修改 props 报警告违反了单向数据流改用emit通知父组件修改或由父组件重新传值点击子组件按钮无反应事件名三处不一致defineEmits/emit/事件让这三处的名字保持完全一致菜单高亮/内容不切换父组件监听函数未更新响应式数据确认函数中修改了对应的ref/reactive状态关键代码速查!-- 父组件传递数据 监听事件 -- AppHeader title后台管理系统 :user-infouserInfo logouthandleLogout / !-- 子组件接收 Props 声明 -- script setup const props defineProps({ title: { type: String, default: 默认标题 }, userInfo: { type: Object, default: () ({ name: 游客 }) } }) /script !-- 子组件 Emit 声明与触发 -- script setup const emit defineEmits([logout, select-menu]) emit(select-menu, { name: 用户管理 }) // 带参 /script