【Vue】组件自定义事件 TodoList 自定义事件数据传输
目录
一、绑定
二、解绑
组件自定义事件总结
TodoList案例对数据传输事件的修改
总结不易~ 本章节对我有很大收获, 希望对你也是!!!
本章节素材已上传Gitee:yihaohhh/我爱Vue - Gitee.com
前面我们学习的clikc、keyup……等一系列为js内置的事件(给HTML元素用的),现在我们就要学习组件的自定义事件(给组件用的!)!
一、绑定
现在想一个问题,把子元素传给父元素有几种办法!
按照我们的进度, 现在只会通过props方法来得到App的函数然后进行传参这一种办法进行
那么现在就来介绍第二种办法:组件自定义事件_绑定
- v-on:事件名="方法" 就是监听子组件触发的自定义事件。这个事件得由子组件用 $emit('事件名') 发出来。
- 给谁绑定事件 就找谁触发 给Student组件的实例对象
- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据 (第一种写法 使用@或者v-on)
<!-- <Student v-on:atwhuc="getStudentName"/> --><Student @atwhuc="getStudentName"/>
大白话就是:“你每次喊一声
atwhuc
,我就立刻执行getStudentName()
这个方法。你喊一次我就干一次,喊十次我就干十次。” 这个事件绑定在Student组件上
Student组件:
<template><div class="student"><h1>{{ msg }}</h1><h2>学生姓名:{{ name }}</h2><h2>学生性别:{{ sex }}</h2><button @click="sendStudentName">把学生名给App</button></div>
</template><script>
export default {name:'Student',data() {return {msg:'我是一个武汉传媒学院的学生',name:'张三',sex: '男' }},methods: {sendStudentName() {// 触发Student的实例身上的atwhuc事件 // 该事件被触发 就让给方法传入了this.$emit('atwhuc', this.name, 666, 888, 999)}}}
</script><style scoped>.student {background-color: orange;padding: 5px;margin-top: 30px;}
</style>
这一种写法是通过在子组件中触发 $emit('atwhuc', 数据)
来发送一个自定义事件 'atwhuc'
,父组件通过 @atwhuc="方法"
监听这个事件,从而实现父子组件之间的传值和通信。
在子组件中用
$emit
是在向父组件发消息,这条消息就叫“自定义事件”。 有通知的意思
📌 补充说明(理解更深一点):
-
子组件不需要知道父组件的具体方法名,只管发事件(松耦合)。
-
父组件监听这个事件并调用自己的方法,同时可以接收
$emit
传来的数据。
但是这么直接用,有点局限性,我们可以更灵活一点!
通过父组件给子组件绑定一个自定义事件实现:子给父传递数据 (第二种写法 使用ref)
<Student ref="student"/>
methods: {getSchoolName(name) {console.log('App收到了学校名', name)},getStudentName(name, ...params) {// params 是一个数组console.log('App被调用!', name, params)}},
// 放一个生命周期钩子mounted() {// 灵活性强 setTimeout(() => {this.$refs.student.$on('atwhuc', this.getStudentName)}, 3000)this.$refs.student.$on('atwhuc', this.getStudentName) // 绑定自定义事件// 只触发一次this.$refs.student.$once('atwhuc', this.getStudentName) // 绑定自定义事件(一次性)}
this.$refs.student:
- 就是你在 HTML 里写的 <Student ref="student" />,
- 相当于你给这个组件起了个小名,方便后面找到它。
$on 当……时:
- $on('atwhuc', this.getStudentName):
- 是你在监听这个组件有没有“发出”一个叫 atwhuc 的信号。
- 如果发了,那就去执行 getStudentName 这个方法。
二、解绑
对于事件的解绑 也是通过实践绑定来通过函数调用完成!
<button @click="unbind">解绑atwhuc事件</button>
unbind() {this.$off('atwhuc') // 只适用于解绑一个自定义事件// emitter.off 代替 $off// $on emitter.on// $emit emitter.emit}
可以发现this.$off 只能进行单个事件的解绑
解绑多个事件,用一个数组进行存储事件!
this.$off(['atwhuc', 'demo'])
更暴力的办法, 全部都解绑!
this.$off() // 全部都解绑
销毁当前组件的全部实例
<button @click="death">销毁当前Student组件的实例(vc)</button>
death() {this.$destroy() // 销毁了当前的组件实例 销毁后 所有Student实例的自定义事件全都不奏效了}
本章节素材已上传Gitee:yihaohhh/我爱Vue - Gitee.com
组件自定义事件总结
想要把Student子组件的name传给父组件 可以用函数来接受Student的name值, 然后更新App组件的studentName的值
这是可行的!
<h1>{{ msg }}, 学生姓名是:{{ studentName }}</h1>
getStudentName(name, ...params) {// params 是一个数组console.log('App被调用!', name, params),this.studentName = name},
this.$refs.student.$on('atwhuc', function(name, ...params) {console.log('App被调用!', name, params),this.studentName = name}) // 绑定自定义事件
用ref也是可行的!
<Student ref="student"/>mounted() {this.$refs.student.$on('atwhuc', this.getStudentName) // 绑定}
但是当我们将getStudentName注释掉之后直接在生命周期钩子里面写回调函数发现this.studentName却不能被赋值了!
this.$refs.student.$on('atwhuc', function(name, ...params) {console.log('App被调用!', name, params),this.studentName = name}) // 绑定自定义事件
点击后不起作用,但是控制台仍然会被执行!
那么我们就重新对this进行打印,来进行观察!
this.$refs.student.$on('atwhuc', function(name, ...params) {console.log('App被调用!', name, params),console.log(this)this.studentName = name}) // 绑定自定义事件
能够发现这些都是Student组件中才存在的, 只能说明 这个this就不是指向App组件的this ,而是Student组件的this
说明Vue的底层就是说明谁触发了‘atwhuc’这个事件, 那么这个事件的回调就会指向谁
那么就说明当我们写成箭头函数的时候:这个this就又重新回到了App组件上
this.$refs.student.$on('atwhuc', (name, ...params)=> {console.log('App被调用!', name, params),console.log(this)this.studentName = name}) // 绑定自定义事件
那么组件可以用自定义事件,能不能用原生事件呢???点击事件呢??
<Student ref="student" @click="show"/>
show() {alert(123)}
可以发现其实并没效果! 原因就是这么写Vue就自动默认把click当作是一个自定义事件,要触发自定义事件,就必须要在Student组件上用$emit,就会进行触发了!
sendStudentName() {// 触发Student的实例身上的atwhuc事件 // 该事件被触发 就让给方法传入了this.$emit('atwhuc', this.name, 666, 888, 999)this.$emit('demo') // 自定义事件名this.$emit('click')},
那么我们只需要添加一个修饰符,就可以让Vue明白我们这是一种原生事件, .native
<Student ref="student" @click.native="show"/>
-
一种组件间通信的方式,适用于:<strong style="color:red">子组件 ===> 父组件</strong>
-
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(<span style="color:red">事件的回调在A中</span>)。
-
绑定自定义事件:
-
第一种方式,在父组件中:
<Demo @atguigu="test"/>
或<Demo v-on:atguigu="test"/>
-
第二种方式,在父组件中:
<Demo ref="demo"/>......mounted(){this.$refs.xxx.$on('atguigu',this.test)}
-
若想让自定义事件只能触发一次,可以使用
once
修饰符,或$once
方法。触发自定义事件:
this.$emit('atguigu',数据)
-
-
解绑自定义事件
this.$off('atguigu')
-
组件上也可以绑定原生DOM事件,需要使用
native
修饰符。 -
注意:通过
this.$refs.xxx.$on('atguigu',回调)
绑定自定义事件时,回调<span style="color:red">要么配置在methods中</span>,<span style="color:red">要么用箭头函数</span>,否则this指向会出问题!
本章节素材已上传Gitee:yihaohhh/我爱Vue - Gitee.com
TodoList案例对数据传输事件的修改
对于子组件给父组件进行数据传输,就可以不在需要用props来传递一个函数,然后进行数据传输, 可以直接采用$emit来触发父组件的自定义事件
那么同理,框起来的全部都是传入的函数, 都是可以将props改写为$emit来进行数据传输,而todos是一个数据不能修改为函数进行传递,就不能用$emit来进行修改
都可以换种方式来获取自定义事件~