Vue 组件通信核心知识点梳理
在初学 Vue 时对组件概念和通信逻辑一直似懂非懂。经过实际项目开发沉淀后重新梳理组件全套核心知识点包含组件意义、单文件组件、组件关系、全套通信方式条理清晰如果错误欢迎指正。一、为什么要使用组件组件化核心价值代码复用减少重复开发通用模块按钮、弹窗、分页、卡片只需编写一次全局多处复用大幅减少冗余代码。代码拆分结构清晰将庞大页面按功能拆分为多个小组件分而治之代码层级清晰便于阅读查找。独立作用域防止污染组件 JS 变量私有、CSS 可通过 scoped 隔离避免全局变量、样式冲突。逻辑封装降低维护成本复杂业务逻辑封装在组件内部外部只需调用即可需求变更只需修改对应组件。按需加载优化页面性能配合路由懒加载、异步组件非首屏组件按需加载减小首屏资源体积提升页面渲染速度。二、什么是单文件组件SFC单文件组件是 Vue 工程化项目的标准开发方式后缀为.vue将一个组件的结构、逻辑、样式三合一封装在同一个文件中。一个标准单文件组件包含三部分template书写页面 HTML 结构script setup书写组件 JS 业务逻辑、数据、方法、导入依赖style scoped书写当前组件专属样式scoped 实现样式隔离三、组件之间的关系项目中所有组件通信都基于三种层级关系父子组件组件直接嵌套引用最常用兄弟组件共用同一个父组件平级互不嵌套祖孙组件多层嵌套爷爷-父-孙子隔层级关系组件核心难点不同关系的组件数据传递通信四、父子组件通信最核心1. 父传子props 单向传值原理父组件通过自定义属性绑定数据子组件通过 props 接收数据单向数据流只能父改子子不能直接修改 props。代码示例父组件 Parent.vuetemplate !-- 动态绑定数据传给子组件 -- Child :msgtitle :listtableList / /template script setup import Child from ./Child.vue const title 父组件传递的文字 const tableList [1,2,3] /script子组件 Child.vuetemplate div p{{ msg }}/p p{{ list }}/p /div /template script setup // 简单接收 // const props defineProps([msg, list]) // 项目规范写法类型校验 必填 默认值 const props defineProps({ msg: { type: String, required: true }, list: { type: Array, default: () [] // 引用类型默认值必须通过函数返回 } }) console.log(props.msg) /script2. 子传父defineEmits 自定义事件原理子组件通过defineEmits声明自定义事件调用emit触发事件并携带参数父组件监听对应事件接收子组件数据。代码示例子组件 Child.vuetemplate button clicksendData向父组件传值/button /template script setup // 声明自定义事件 const emit defineEmits([send]) const sendData () { // 触发事件携带多个参数传给父组件 emit(send, 子组件的数据, 1232321) } /script父组件 Parent.vuetemplate Child sendgetChildData / /template script setup // 接收子组件传递的参数 const getChildData (val1, val2) { console.log(val1, val2) } /script3. 父子双向绑定语法糖defineModel本质props emit 的语法糖简化双向绑定代码Vue3 推荐使用。代码示例子组件template input v-modelmodelValue / /template script setup // 快速实现双向绑定 const modelValue defineModel() /script父组件template Child v-modelnum / /template script setup const num ref(0) /script4. 父获取子实例/方法ref defineExpose原理默认子组件内部属性、方法对外封闭子组件通过defineExpose主动暴露内容父组件通过 ref 获取子组件实例调用子组件变量和方法。代码示例子组件 Child.vuescript setup import { ref } from vue const childMsg ref(子内部变量) const childFn () { alert(子组件方法) } // 主动暴露给父组件 defineExpose({ childMsg, childFn }) /script父组件 Parent.vuetemplate Child refchildRef / button clickcallChild调用子方法/button /template script setup import { ref } from vue const childRef ref(null) const callChild () { console.log(childRef.value.childMsg) childRef.value.childFn() } /script五、祖孙组件通信跨层级祖孙组件多层嵌套不推荐 props 逐层透传中间组件冗余主流两种方案provide/inject、事件总线 mitt。1. provide / injectVue 原生首选核心原理provide祖先组件爷爷提供数据/方法向下穿透所有后代组件inject任意后代组件直接注入使用跳过中间所有层级1.1 传递静态数据爷爷组件template Father / /template script setup import { provide } from vue provide(grandMsg, 爷爷的静态文字) /script孙子组件script setup import { inject } from vue const msg inject(grandMsg) console.log(msg) /script1.2 传递响应式数据项目常用普通静态数据无响应式祖先更新数据后代不生效需传递 ref 响应式数据。爷爷组件script setup import { ref, provide } from vue const grandNum ref(100) // 提供响应式数据 provide(grandNum, grandNum) // 提供修改数据的方法 const changeNum () { grandNum.value 10 } provide(changeNum, changeNum) /script孙子组件template p爷爷数字{{ num }}/p button clickaddFn调用爷爷方法修改/button /template script setup import { inject } from vue const num inject(grandNum) const addFn inject(changeNum) /script1.3 孙子向祖先反向传值思路爷爷向外暴露修改自身数据的方法孙子调用该方法完成传值。爷爷组件script setup import { ref, provide } from vue const text ref() const setText (val) { text.value val } provide(setText, setText) /script孙子组件script setup import { inject } from vue const setText inject(setText) const sendToGrand () { setText(孙子传给爷爷的数据) } /script1.4 inject 默认值防报错// 若祖先未提供对应数据使用默认空值避免报错constmsginject(grandMsg,)2. 祖孙通信mitt 事件总线原理通过全局总线实现孙子 → 爷爷主动传值适合后代主动触发通知的场景。孙子组件发送数据import{bus}from/utils/busbus.emit(son-to-grand,孙子消息)爷爷组件监听数据import{bus}from/utils/busimport{onMounted,onUnmounted}fromvueonMounted((){bus.on(son-to-grand,(data){console.log(收到孙子数据,data)})})// 组件销毁必须解绑防止内存泄漏onUnmounted((){bus.off(son-to-grand)})优缺点✅ 适合子孙主动向顶层祖先发送通知、回调❌ 需手动解绑事件大型项目易出现事件名冲突六、核心总结组件化核心复用、拆分、隔离、易维护、高性能单文件组件.vue 文件结构、逻辑、样式三位一体父子通信props父传子、emit子传父、defineModel双向绑定、ref父控子祖孙通信优先provide/inject原生简洁主动通知用mitt注部分内容可能由 AI 生成