【Vue】第十二部分 组件间的通信(自定义事件、全局事件总线、消息订阅发布)很重要
文章目录
12. 组件间的通信(自定义事件、全局事件总线、消息订阅发布)
12.1 组件自定义事件
-
作用:可以实现子组件 ==> 父组件通信
-
假设:A:父组件,B:子组件,当B想给A传数据的时候,那么A需要事先给B绑定自定义事件(事件的回调要留在A),在B中去触发自定义事件并且把想要传的参数写进去,由于自定义事件的触发导致回调函数被调用就可以接收到数据。
12.1.1 绑定自定义事件的方法
第一种方法:通过v-on(@)进行绑定
<template>
//在school组件上绑定hello事件,如果hello事件被触发就调用showinfo函数,该回调留在APP组件上
<school @hello = "showinfo"></school>
//<school @hello.once = "showinfo"></school>
</template>
<script>
export default {
name:"APP",
methods:{
showinfo(){
console.log("该函数被调用")
}
}
}
</script>
第二种方法:通过ref打标签,需要配合$on()进行绑定
<template>
// 通过打标签的形式需要配合挂载
<school ref = "hello"></school>
</template>
<script>
export default {
name:"APP",
methods:{
showinfo(){
console.log("该函数被调用")
}
},
mounted(){//挂载
/*
下面这行代码的意思是:因为我们给组件绑定ref所以返回的是该组件的实例化对象,
相当于给vc绑定一个叫Demo事件,如果Demo触发就调用shiowinfo函数
*/
this.$refs.hello.$on("Demo",this.showinfo)
// 如果想要执行一次就可以使用$once修饰符
// this.$refs.hello.$once("Demo",this.Demo)
}
}
</script>
触发自定义事件
this.$emit('自定义事件名',参数...)
解绑自定义事件
this.$off('自定义事件名')
只能解绑一个事件
this.$off()
12.1.2 比较props和自定义组件
下面两个例子都是子组件向父组件传数据的例子
props的方式
school组件(子组件)
<template>
<div>
<h3>名字:{{name}}</h3>
<h3>地址:{{address}}</h3>
<button @click="showinfo">点击输出基本信息</button>
</div>
</template>
<script>
export default {
name:"School",
data(){
return{
name:"Jack",
address:"China"
}
},
methods:{
showinfo(){
//使用函数
this.info(this.name,this.address)
}
},
//接收App传进来的函数
props:["info"]
}
</script>
APP组件(父组件)
<template>
<!-- 向school组件传一个info函数 -->
<school :info = "info"></school>
</template>
<script>
import School from "./components/School.vue"
export default {
name:"App",
components:{School},
methods:{
info(name,address){
console.log(name+"--"+address);
}
}
}
</script>
自定义组件的方式
school组件(子组件)
<template>
<div>
<h3>名字:{{name}}</h3>
<h3>地址:{{address}}</h3>
<button @click="showme">点击输出基本信息</button>
</div>
</template>
<script>
export default {
name:"School",
data(){
return{
name:"Jack",
address:"China"
}
},
methods:{
showme(){
// 触发info事件并且传入参数
this.$emit("info",this.name,this.address)
}
}
}
</script>
APP组件(父组件)
<template>
<!-- 给school组件绑定info事件,当info事件触发就调用showinfo函数 -->
<school @info="showinfo"></school>
</template>
<script>
import School from "./components/School.vue"
export default {
name:"App",
components:{School},
methods:{
showinfo(name,address){
console.log(name+"--"+address);
}
}
}
</script>
12.1.3 组件自定义事件总结
- 上面两种方式只适用子组件向父组件通信
- 如果是隔代组件或兄弟组件间通信此种方式不合适
- 若想让自定义事件只能触发一次,可以使用
once
修饰符,或$once
方法 - 解绑自定义事件
this.$off('自定义事件名')
- 组件上也可以绑定原生DOM事件,需要使用
native
修饰符。 - 注意:通过
this.$refs.xxx.$on('自定义事件名',回调)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
12.2 全局事件总线 (很重要)
12.2.1 原理和概念
原理:利用==组件自定义事件==配合内置关系
作用:实现任意组件之间通信
安装全局事件总线
new Vue({
beforeCreate(){
/*
安装全局事件总线 $bus = this = vm
为什么下面代码就可以完成全局事件总线?
因为它满足2个条件:
1.所有的组件都可以看见之前讲过一个重要的内置关系
vueComponent.prototype._proto_ === Vue.prototype
2.它满足$on,$emit,$off这些相关的API
*/
Vue.prototype.$bus = this
}
})
12.2.2 使用全局事件总线
小总结:
-
谁想要接收数据就在哪个组件下给$bus绑定自定义事件,事件回调也在组件中
-
提供数据的那一个组件去$bus中触发自定义事件
test组件
<template>
<div>
<h3>大家好!我是{{name}}</h3>
<h3>我来自{{address}}</h3>
<button @click="show">点我</button>
</div>
</template>
<script>
export default {
data(){
return{
name:"Jack",
address:"China"
}
},
methods:{
show(){
this.$bus.$emit("Demo",this.name,this.address)
}
}
}
</script>
<style>
</style>
school组件
<template>
<div>
<h3>我是school组件</h3>
</div>
</template>
<script>
export default {
name:"school",
methods:{
showinfo(name,address){
console.log(name+"-"+address);
}
},
mounted(){
this.$bus.$on("Demo",this.showinfo)
}
}
</script>
<style>
</style>
12.2.3 解绑
最好养成一个好的习惯在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
export default {
name:"school",
methods:{
showinfo(name,address){
console.log(name+"-"+address);
}
},
mounted(){
this.$bus.$on("Demo",this.showinfo)
},
beforeDestroy(){
this.$bus.$off("Demo")
}
}
12.3 消息订阅发布
12.3.1 准备工作
在这里是用到了PubSubJS 库
使用的步骤:
-
安装pubsub:
npm i pubsub-js
-
引入:
import pubsub from 'pubsub-js'
-
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。(其实和全局事件总线使用的思路是一样的)
-
订阅消息(接收数据):
PubSub.subscribe('xxx', function(xxx, 数据){})
-
发布消息(提供数据):
pubsub.publish('xxx',数据)
-
最好在beforeDestroy钩子中,用
PubSub.unsubscribe(pid)
去取消订阅。这里需要注意如果要取消订阅要获取订阅的id才可以去取消
const pid = PubSub.subscribe('xxx', function(xxx, 数据){})
它返回的结果就是订阅id
12.3.2 订阅消息和发布消息
订阅消息
PubSub.subscribe('msg', function(msgName, data){})
msg:表示事件名
msgName:也表示事件名
data:表示收到的数据
发布消息
PubSub.publish('msg', data)
msg:表示事件名
data:表示要传入的数据
12.3.3 案例
school组件
<template>
<div class="school">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</template>
<script>
//导入pubsub
import pubsub from 'pubsub-js'
export default {
name:'School',
data() {
return {
name:'清华大学',
address:'北京',
}
},
mounted() {
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log(this) //因为写了箭头函数this指向vc
console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})
},
beforeDestroy() {
pubsub.unsubscribe(this.pubId)
},
}
</script>
<style scoped>
.school{
background-color: skyblue;
padding: 5px;
}
</style>
student组件
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<button @click="sendStudentName">把学生名给School组件</button>
</div>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
mounted() {
// console.log('Student',this.x)
},
methods: {
sendStudentName(){
pubsub.publish('hello',this.name)
}
},
}
</script>
<style lang="less" scoped>
.student{
background-color: pink;
padding: 5px;
margin-top: 30px;
}
</style>
总结
以上就是今天要讲的内容,本文介绍了组件间的通信(自定义事件、全局事件总线、消息订阅发布),希望对大家有所帮助!