当前位置: 首页 > news >正文

Vue基础知识-脚手架开发-子传父-props回调函数实现和自定义事件($on绑定、$emit触发、$off解绑)实现

一、项目概况与结构

本文通过「App 父组件」+「School 子组件」+「Student 子组件」演示两种子传父方式:

  • School 组件:用「props 回调函数」传递学校名称(北京大学)给 父App;
  • Student 组件:用「自定义事件」传递学生名称(张三)给 父App,同时演示事件解绑;
  • App 组件:作为父组件,接收并展示子组件传递的数据。

项目结构(Vue 2 标准结构):

src/
├─ components/       # 子组件目录
│  ├─ School.vue     # props回调演示
│  └─ Student.vue    # 自定义事件演示
├─ App.vue           # 父组件(整合子组件)
└─ main.js           # 入口文件(初始化Vue)

二、完整代码实现

1. 入口文件:main.js


import Vue from 'vue'import App from './App.vue'Vue.config.productionTip = falsenew Vue({render: h => h(App),
}).$mount('#app')

2. 子组件 1:School.vue(props 回调函数实现子传父)

核心逻辑:父组件传递一个回调函数给子组件(通过 props),子组件调用该函数并传入数据,父组件在回调中接收数据。

<template><div class="demo"><h2>学校名称:{{name}}</h2><input type="button" value="传递学校名(props实现)" @click="sendSchoolName()" /></div>
</template>
<script>export default {name:'School',data(){return {name:'北京大学'}},props:['getSchoolName'],methods:{sendSchoolName(){this.getSchoolName(this.name)}}}
</script><style scoped>.demo{background-color: red;padding:10px;}
</style>

3. 子组件 2:Student.vue(自定义事件实现子传父)

核心逻辑:父组件给子组件绑定自定义事件,子组件通过this.$emit('事件名', 数据)触发事件,父组件在事件回调中接收数据;同时演示事件解绑(this.$off)。

<template><div class="demo"><h2>学生名称:{{name}}</h2><input type="button" value="传递学生名(自定义事件实现)" @click="sendStudentlName" /><input type="button" value="解绑自定义事件" @click="unbind" /></div>
</template>
<script>export default { name:'Student',data(){return {name:'张三'}},methods:{sendStudentlName(){//触发自定义事件@getStudentName,并传入参数this.$emit('getStudentName',this.name)},unbind(){//解绑一个this.$off('getStudentName')//解绑多个this.$off(['getStudentName','xx'])//解绑所有this.$off()}}}
</script><style scoped>.demo{background-color: orange;padding: 10px;margin-top: 30px;}
</style>

4. 父组件:App.vue(接收子组件数据)

作为父组件,分别用两种方式接收子组件数据,并展示结果;同时演示自定义事件的 “手动绑定” 和@click.native的用法。

<template><div class="app"><h2>学校名称:{{schoolName}}</h2><h2>学生名称:{{studentlName}}</h2><!--使用props实现子传父:父传回调函数getSchoolName给子调用。本质调父的getSchoolName(子写props接收并调用)--><School :getSchoolName="getSchoolName"/><!--使用自定义事件实现子传父:父给子绑定自定义事件并由子来触发。(子写this.$emit('',args[])触发自定义事件)--><!--  第一种实现:直接绑定(@用于组件上)。当Student实例触发@getStudentName事件,getStudentName调用。要求触发一次:@getStudentName加上.once即可<Student @getStudentName="getStudentName"/>--><!--  第二种实现:手动绑定。--><Student ref="student"/><!-- 注:<Student @click.native="nativeClick"/>@click.native表示单击事件(最终绑定在Student组件里template的根div)。不加native会被当作自定义事件。 --></div>
</template><script>import School from './components/School'  import Student from './components/Student';    export default {name:'App',data() {return {schoolName:'',studentlName:''}},components:{School,Student},methods:{getSchoolName(schoolName){this.schoolName = schoolName},getStudentName(studentlName){this.studentlName = studentlName},nativeClick(){alert('原生事件')}},mounted(){/* 第二种实现,手动绑定:当Student实例触发@getStudentName事件,getStudentName调用。要求触发一次:this.$refs.student.$once('getSstudentName',this.getStudentName) */this.$refs.student.$on('getStudentName',this.getStudentName)/* 写生匿名函数注意this指向问题:下面的this指向App组件,若不写箭头函数则this指向Student组件导致错误。this.$refs.student.$on('getStudentName',(studentlName)=>{this.studentlName = studentlName})  */}}
</script><style>.app{background-color: gray;padding: 10px;}</style>

三、核心知识点深度解析

1. 方式一:props 回调函数实现子传父

原理

父组件定义一个 “接收数据的回调函数”,通过props将该函数传递给子组件;子组件调用这个回调函数时,将内部数据作为参数传入,父组件在回调中拿到数据并更新自身状态。

关键步骤(3 步)
  1. 父组件定义回调函数:如getSchoolName(schoolName) { this.schoolName = schoolName }
  2. 父传子:通过 props 传递回调<School :getSchoolName="getSchoolName" />
  3. 子传父:调用回调函数传数据:子组件props: ['getSchoolName']接收,this.getSchoolName(this.name)触发传递。
优缺点
  • 优点:逻辑简单,代码量少,适合 “一次性传递” 或 “简单场景”;
  • 缺点:不支持事件解绑,若子组件多次触发,父组件无法主动停止接收;且 props 本质是 “数据传递”,用它传函数不符合 “props 仅传数据” 的设计初衷(语义化稍差)。

2. 方式二:自定义事件实现子传父

原理

Vue 组件实例自带事件系统($on绑定、$emit触发、$off解绑),父组件给子组件绑定一个 “自定义事件”,子组件通过$emit触发该事件并传递数据,父组件在事件回调中接收数据;可通过$off主动解绑事件,避免内存泄漏。

两种绑定方式(灵活选择)
绑定方式语法示例适用场景
模板直接绑定<Student @getStudentName="getStudentName" />简单场景,推荐优先使用
手动绑定($refs)this.$refs.studentRef.$on('事件名', 回调)需动态绑定 / 解绑(如条件绑定)
事件解绑(3 种场景)
  • 解绑单个事件:this.$off('事件名')(如 Student 组件的this.$off('getStudentName'));
  • 解绑多个事件:this.$off(['事件1', '事件2'])
  • 解绑所有事件:this.$off()(谨慎使用,会解绑组件所有自定义事件)。
优缺点
  • 优点:语义化清晰(专门用于 “事件通信”),支持绑定 / 解绑,适合 “多次触发” 或 “需要动态控制” 的场景;
  • 缺点:代码量略多,需理解 Vue 组件的事件系统($on/$emit/$off)。

3. 补充:@click.native 的作用

在组件标签上用@click时,Vue 默认将其视为 “自定义事件”(需子组件$emit('click')才触发);若想绑定组件根 DOM 的原生 click 事件,需加native修饰符:

  • 错误用法:<Student @click="handleClick" />(子组件需$emit('click')才触发);
  • 正确用法:<Student @click.native="handleClick" />(直接绑定子组件根 DOM 的原生 click 事件,无需子组件处理)。

原理native修饰符会 “穿透组件”,将事件绑定到子组件的根 DOM 元素上,本质是监听原生 DOM 事件(如clickinput)。

四、两种子传父方式对比总结

对比维度props 回调函数自定义事件
实现原理父传回调函数,子调用传参父绑定事件,子 $emit 触发传参
绑定方式仅模板绑定(:props="回调")模板绑定(@事件名)/ 手动绑定(refs.on)
事件解绑❌ 不支持✅ 支持($off)
触发次数控制❌ 无(子组件可无限次调用)✅ 支持单次触发($once)
语义化稍差(props 本应传数据,而非函数)优(专门用于事件通信)
适用场景简单场景、一次性传递(如初始化数据)复杂场景、多次触发、需解绑(如交互操作)
代码复杂度低(3 步完成)中(需理解事件 API)

五、注意事项

  1. 单向数据流:无论哪种方式,都遵循 Vue “单向数据流” 原则 —— 子组件仅传递数据,不直接修改父组件数据;父组件接收数据后自行更新,确保数据流向可追溯。
  2. 事件名大小写:自定义事件名推荐用 “kebab-case”(短横线命名),如get-student-name,避免用 “camelCase”(驼峰命名)(Vue 模板中不区分大小写,可能导致事件名匹配失败)。
  3. 手动绑定时机:通过$refs手动绑定事件时,需在mounted钩子中执行(确保子组件已挂载,$refs能获取到组件实例),避免在created中执行(此时子组件未渲染,$refsundefined)。
  4. 内存泄漏:若子组件是 “动态渲染”(如v-if控制显示隐藏),建议在组件卸载前用$off解绑事件,避免事件残留导致内存泄漏。

六、总结

Vue 子传父的两种方式各有适用场景:

  • 简单场景(如一次性传递初始化数据):优先用props 回调函数,代码简洁;
  • 复杂场景(如多次交互、需动态解绑):优先用自定义事件,语义化清晰且灵活。

无论选择哪种方式,核心都是遵循 “单向数据流”,让父组件统一管理数据,确保项目后期可维护性。


文章转载自:

http://HQM2BTlQ.qjbxt.cn
http://ZCDm7Ilj.qjbxt.cn
http://tLcB8Mx3.qjbxt.cn
http://0LMWht19.qjbxt.cn
http://EW3BEk9N.qjbxt.cn
http://N3Y6Iy19.qjbxt.cn
http://DrfrkfsQ.qjbxt.cn
http://HyCs7MoP.qjbxt.cn
http://2vr5fxNs.qjbxt.cn
http://GtOwfix1.qjbxt.cn
http://WZfcXaHT.qjbxt.cn
http://IcgeazMT.qjbxt.cn
http://FNwS8S1p.qjbxt.cn
http://rLiVkiHg.qjbxt.cn
http://YesNtPCz.qjbxt.cn
http://bUiZ8idh.qjbxt.cn
http://MHxgQLyc.qjbxt.cn
http://1gGNTTFz.qjbxt.cn
http://uJTgMwrP.qjbxt.cn
http://W25RN2Z3.qjbxt.cn
http://rd9fSWAF.qjbxt.cn
http://SmGRSuD1.qjbxt.cn
http://xUhUuXLA.qjbxt.cn
http://6OxcOAm7.qjbxt.cn
http://pgZtSqg5.qjbxt.cn
http://kRSCys6x.qjbxt.cn
http://CProxG3P.qjbxt.cn
http://bOSldvY6.qjbxt.cn
http://9SaD8Bud.qjbxt.cn
http://5KKXAfnQ.qjbxt.cn
http://www.dtcms.com/a/367620.html

相关文章:

  • 铭记抗战烽火史,科技强企筑强国 | 金智维开展抗战80周年主题系列活动
  • 无人机信号防干扰技术难点分析
  • 企业白名单实现【使用拦截器】
  • 硬件(二) 中断、定时器、PWM
  • 11 月广州见!AUTO TECH China 2025 汽车内外饰展,解锁行业新趋势
  • 【multisim汽车尾灯设计】2022-12-1
  • 工业人形机器人运动速度:富唯智能重新定义智能制造效率新标准
  • 惊爆!耐达讯自动化RS485转Profinet,电机连接的“逆天神器”?
  • Android 权限管理机制
  • MATLAB平台实现人口预测和GDP预测
  • jQuery的$.Ajax方法分析
  • 实现自己的AI视频监控系统-第三章-信息的推送与共享4
  • Vben5 封装的组件(豆包版)
  • 研发文档更新滞后的常见原因与解决方法
  • AI工具深度测评与选型指南 - Lovart专题
  • 卡方检验(独立性检验)
  • 【C语言】第四课 指针与内存管理
  • Mac开发第一步 - 安装Xcode
  • Full cycle of a machine learning project|机器学习项目的完整周期
  • AES介绍以及应用(crypto.js 实现数据加密)
  • 四十岁编程:热爱、沉淀与行业的真相-优雅草卓伊凡
  • 【数据分享】中国城市营商环境数据库2024(296个城市)(2017-2022)
  • 结合prompt分析NodeRAG的build过程
  • 2025数学建模国赛高教社杯B题思路代码文章助攻
  • Nano-Banana使用教程
  • 在Spring MVC中使用查询字符串与参数
  • Unity中,软遮罩SoftMaskForUGUI的使用
  • Websocket的Key多少个字节
  • 手写Java泛型,彻底掌握它!
  • Redlock:为什么你的 Redis 分布式锁需要不止一个节点?