二十四. vue中组件通信的方式有哪些?(面试频率高)

一. props属性

用于父——>子组件通信。(当然,也可实现子——>父组件通信,但是很麻烦。需要父组件传给组件一个函数,子组件接收这个函数,然后子组件再给这个函数传值,调用这个函数。简单的说就是“子组件调用父组件传过来的函数”,感觉这并不是真正的“子——>父组件通信”)

1. 个人理解

  • 相当于微信转账!一方发送数据,一方接收数据!
  • 发送方需要使用“单项绑定v-bind”对要传送的数据进行绑定,要不然会只发送字符串
  • 接收方有多种权力,通过配置可对传送类型进行限制,可限制是否必要性,可指定默认值
  • props中接收的数据,不会存入data中,但是却比data中的数据先加载(优先级高)
  • props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

2. 举例:

(1)例1:父——>子组件通信

发送方:

<template>
	<div>
		<Student name="李四" sex="" :age="18"/>
	</div>
</template>

接收方:

//简单声明接收
props:['name','age','sex']

//接收的同时对数据进行类型限制
props:{
	name:String,
	age:Number,
	sex:String
}

//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
	name:{
		type:String, //name的类型是字符串
		required:true, //name是必要的
	},
	age:{
		type:Number,
		default:99 //默认值
	},
	sex:{
		type:String,
		required:true
	}
}

(2)例2:子——>父组件通信

发送方(父组件):

<School :name="getName"/>
...
// js代码
methods:{
	getName(name){ console.log('名称',name}
}

接收者(子组件):

//student.vue
<button @click="sendName">子组件调用父组件传过来的函数</button>
...
// js代码
data(){
	return{
		name:'小明'
	}
},
props:['getName'],
methods:{
	sendName(){
		this.getName(this.name)
	}
}

二. 自定义事件$on$emit$off

可实现子——>父通信

1. 个人理解

  • 上述通过props也可实现子——>父通信,是子组件调用父组件传过来的方法,回调函数还是在父组件。但是这样非常麻烦,还需要使用props属性接收。而使用自定义事件实现子——>父通信就方便很多!两者有个共同点,那就是回调函数都是在父组件!
  • 自定义事件理解:在父组件给子组件实例绑定自定义事件。然后子组件就可调用自己实例上的绑定的自定义事件。感觉大致还是和通过props属性实现子——>父通信差不多!
  • 到底该如何理解自定义事件可实现子——>父通信?可通过父组件的函数调用子组件中的数据
  • 如何在自定义组件上使用原生事件?不错,默认自定义组件认定原生事件为自定义事件,需要使用native关键字,例@click.native="show"
  • 使用自定义事件完成子——>父通信有两种方式。一是通过@或v-on直接绑定自定义事件,二是通过指定ref属性和$on$once来完成自定义事件绑定!两种方式都是在子组件中通过$emit调用自定义事件!
  • 销毁了当前子组件的实例,销毁后所有Student实例的自定义事件全都不奏效,但是原生事件还是奏效!
  • $emit:触发当前实例上的事件
  • $on(eventName, listener): 绑定自定义事件监听(用于单独绑定事件,不是在组件上),需要给子组件标签上配置ref属性然后在mounted方法单独绑定
  • $once(eventName, listener): 绑定事件监听, 但只能处理一次(用于单独绑定事件,不是在组件上),同上。
  • $off(eventName): 解绑自定义事件监听,若不传参则解除绑定所有自定义事件

2. 举例

(1)例1:张天禹老师例子

父组件App:

<template>
	<div class="app">
		<h1>{{msg}},学生姓名是:{{studentName}}</h1>
		<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
		<!-- <Student @hello="getStudentName"/> -->

		<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) @click.native原生绑定测试-->
		<Student ref="student" @click.native="show"/>
	</div>
</template>
<script>
	export default {
		name:'App',
		components:{School,Student},
		methods: {
			getStudentName(name,...params){
				console.log('App收到了学生名:',name,params)
				this.studentName = name
			},
			show(){
				alert(123)
			}
		},
		mounted() {
			this.$refs.student.$on('atguigu',this.getStudentName) //绑定自定义事件
			// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(一次性)
		},
	}
</script>

子组件Student:

<template>
	<div class="student">
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<h2>当前求和为:{{number}}</h2>
		<button @click="add">点我number++</button>
		<button @click="sendStudentlName">把学生名给App</button>
		<button @click="unbind">解绑atguigu事件</button>
		<button @click="death">销毁当前Student组件的实例(vc)</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男',
				number:0
			}
		},
		methods: {
			add(){
				console.log('add回调被调用了')
				this.number++
			},
			sendStudentlName(){
				//触发Student组件实例身上的atguigu事件
				this.$emit('atguigu',this.name,666,888,900)
			},
			unbind(){
				this.$off('atguigu') //解绑一个自定义事件
				// this.$off(['atguigu','demo']) //解绑多个自定义事件
				// this.$off() //解绑所有的自定义事件
			},
			death(){
				this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效,原生事件add还是奏效。
			}
		},
	}
</script>

三. 全局事件总线$bus

1. 定义

  • 可用于任意组件间的通信
  • 全局事件总线$bus并不是一种什么新的api技术,而是程序员把现有的知识总结用起来形成的通信方式,非常好用!称它为全局事件总线$bus
  • 使用全局事件总线$bus需要配置两个要求:1是要求所有组件都能看见$bus;2是要求全局事件总线$bus能调用被调用者的$on$off$emit
  • $bus是程序员共同默认的名字,当然写其他的也行!
  • 全局事件总线$bus,就是一个中间人,像是一个傀儡!!!也因此,它的压力非常大,所以需要使用befpreDestroy钩子函数,通过$off去解绑当前组件所用到的事件!切记不用直接用$off()不传参!
  • 为什么自定义事件中的组件没有强制要求要解绑自定义事件?vc组件用过自动销毁,销毁自动解绑所有自定义事件!而$bus是vm组件实例,不解绑的话压力多大可想而知!

2. 如何使用全局事件总线$bus?

(1)要求所有组件都能看见$bus

在main.js文件中,给vue实例对象上绑定$bus数据
为什么?
三个选项:
1是window(可行,但是使用window不好!)
2是VueComponent实例对象(不可行,每个组件的VueComponent实例对象都不一样)
3是vue实例对象(这个只有一个,可行!!!)
例:Vue.prototype.$bus = {数据}
这里说是根据这个内置关系:VueComponent.prototype.__ proto__ = Vue.prototype,但是这里我有点看不懂,先到这里!以后再看!!!

(2)要求全局事件总线$bus能调用被调用者的$on$off$emit

  • 谁才能调用$on$off$emit,Vue原型对象上才有这几个属性。
  • vc原型对象最终还是调用vue原型对象,看下图。所以vc和vue(vm)原型对象都能调用**$on$off$emit
    在这里插入图片描述
1)vc形式:
2)vm形式:

安装全局事件总线

//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
	//看这里
	beforeCreate() {
		Vue.prototype.$bus = this //安装全局事件总线,也就是说全局事件总线$bus就是vm对象
	},
})

如何使用?
使用也就和自定义事件通信差不多了,接收者通过$on把事件绑定到$bus上,发送数据者然后通过$emit触发事件。
举例:
接收者:

mounted(){
	this.$bus.$on('事件名',回调函数)
}

发送数据者:

this.$bus.$emit('事件名',数据)

四. 消息订阅与发布pubsub-js

即可子——>父,又可父——>子。但是用的少

五. 插槽

可实现父——>子组件通信

六. vuex

即可子——>父,又可父——>子。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值