0
点赞
收藏
分享

微信扫一扫

【Vue】第十二部分 组件间的通信(自定义事件、全局事件总线、消息订阅发布)很重要很重要

生活记录馆 2022-02-27 阅读 22

【Vue】第十二部分 组件间的通信(自定义事件、全局事件总线、消息订阅发布)很重要


文章目录


12. 组件间的通信(自定义事件、全局事件总线、消息订阅发布)


12.1 组件自定义事件

  1. 作用:可以实现子组件 ==> 父组件通信

  2. 假设: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 组件自定义事件总结

  1. 上面两种方式只适用子组件向父组件通信
  2. 如果是隔代组件兄弟组件间通信此种方式不合适
  3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法
  4. 解绑自定义事件this.$off('自定义事件名')
  5. 组件上也可以绑定原生DOM事件,需要使用native修饰符。
  6. 注意:通过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 库

使用的步骤:

  1. 安装pubsub:npm i pubsub-js

  2. 引入: import pubsub from 'pubsub-js'

  3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。(其实和全局事件总线使用的思路是一样的)

  4. 订阅消息(接收数据):PubSub.subscribe('xxx', function(xxx, 数据){})

  5. 发布消息(提供数据):pubsub.publish('xxx',数据)

  6. 最好在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>



总结

以上就是今天要讲的内容,本文介绍了组件间的通信(自定义事件、全局事件总线、消息订阅发布),希望对大家有所帮助!

举报

相关推荐

0 条评论