vue2.x组件通信有哪些方式,vue组件间通信六种方式(完整版)
vue组件的通讯方式,这是面试中出现频率非常高的问题。其实vue组件除了props和$emit还有很多通信方式。本文将总结Vue组件的通信方式,有兴趣的可以借鉴。
目录
1.props/$emit轮廓代码示例2.v形槽轮廓代码示例3。$ refs/$ parent/$ children/$ root配置文件代码示例4。$attrs/$listener profile代码示例5.provide/代码示例注入简介6。6.eventBus介绍原理分析7 .代码示例。7.vuex的代码示例总结了vue组件的通信方式,是面试中出现频率非常高的问题。刚开始找实习的时候经常遇到这个问题。那时候我只知道回道具和$emit。后来随着学习的深入,才发现Vue组件的通信方式竟然这么多!
今天总结一下vue组件的通讯方式,如有遗漏请留言。
1. props/$emit
简介
道具和$emit相信大家都很熟悉。这是我们最常用的vue沟通方式。
Props:props可以是一个数组,也可以是一个对象,用来从父组件接收v-bind传递的数据。当props为数组时,直接接收父组件传递的属性;当props为对象时,可以通过类型、默认值、是否必选、验证器等配置来设置属性的类型、默认值、是否必选以及验证规则。
$emit:父子组件通信时,我们通常用$emit触发父组件v-on绑定子组件上相应的事件进行监听。
代码实例
下面的代码用来实现props和$emit之间的父子组件通信。在这个例子中,我们都实现了以下通信:
将值从父组件传递到子组件:父组件通过:messageFromParent= message 将父组件的消息值传递到子组件。当父组件的输入标签被输入时,子组件的p标签中的内容会相应地改变。
从子组件向父组件传递值:父组件通过@on-receive=receive 将接收事件的监视绑定到子组件上。当子组件的input标签被输入时,receive回调函数会被触发,子组件消息的值会通过这个赋给父组件messageFromChild。$ emit (on-receive ,this.message),更改父组件P标记的内容。
请看代码:
//子组件代码
模板
div class=child
h4这是子组件/h4
input type= text v-model= message @ keyup= send /
p收到来自父组件的消息:{{MessageFromparet}}/p
/div
/模板
脚本
导出默认值{
姓名:孩子,
Props: [MessageFromparet],//通过Props接收来自父组件的消息
data() {
返回{
消息: ,
}
},
方法:{
send() {
这个。$emit (on-receive ,this.message)//通过$emit触发on-receive事件,调用父组件中的receive回调,以this . message为参数。
},
},
}
/脚本
//父组件代码
模板
div class=parent
h3这是父组件/h3
输入类型=text v-model=message /
p收到来自子组件的消息:{{ messageFromChild }}/p
child:message from parent= message @ on-receive= receive /
/div
/模板
脚本
从导入子级。/孩子
导出默认值{
姓名:家长,
data() {
返回{
消息: ,//传递给子组件的消息
messageFromChild: ,
}
},
组件:{
孩子,
},
方法:{
Receive(msg) {//接受子组件的信息,并将其分配给messageFromChild
this.messageFromChild=msg
},
},
}
/脚本
效果预览
2. v-slot
简介
V-slot是2.6版本中新增的统一实现插槽和命名插槽的api,用于替代slot(2.6.0过时)、slot-scope(2.6.0过时)、scope(2.5.0过时)等API。
模板标签中使用V-slot来提供命名插槽或需要接收prop的插槽。如果未指定v-slot,则默认值为default。
代码实例
让我们来看看v-slot的代码示例,我们在其中实现了:
从父到子传递值:父组件通过模板v-slot:child { { message } }/template将父组件的消息值传递给子组件,子组件通过slot name=child/slot接收相应的内容,从而实现父到子的值传递。
//子组件代码
模板
div class=child
h4这是子组件/h4
p收到来自父组件的消息:
slot name=child/slot!-显示父组件通过插槽传递的{{message}}
/p
/div
/模板
模板
div class=parent
h3这是父组件/h3
输入类型=text v-model=message /
儿童
模板v形槽:子
{{ message }}!-插槽会显示什么-
/模板
/孩子
/div
/模板
脚本
从导入子级。/孩子
导出默认值{
姓名:家长,
data() {
返回{
消息: ,
}
},
组件:{
孩子,
},
}
/脚本
效果预览
3. $refs/ $parent/ $children/$root
简介
我们还可以通过$refs/$parent/$children/$root获取Vue组件的实例,获取实例上绑定的属性和方法,从而实现组件之间的通信。
$refs:我们通常将$refs绑定到DOM元素来获取DOM元素的属性。在实现组件通信时,我们还可以将$refs绑定到子组件,以获得子组件实例。
$parent:我们可以通过这个直接得到当前组件的父组件实例(如果有的话)。Vue中的$parent。
$children:同理,我们也可以通过这个直接得到当前组件的子组件实例的数组。Vue的儿童。然而,应该注意的是,元素下标在这个。$children数组不一定会影响父组件引用的子组件的顺序,例如,异步加载的子组件可能会影响它们在子数组中的顺序。所以需要根据一定的条件找到对应的子组件,比如子组件的名称。
$root:获取当前组件树的根Vue实例。如果当前实例没有父实例,则该实例将是自己的实例。通过$root,我们可以实现组件之间的跨层通信。
代码实例
让我们来看一个使用$ parent和$ children的例子。(由于这些API的使用方式相似,所以这里不展开$ refs和$ root的使用。它在本例中实现:
将值传递给父组件和子组件:子组件通过$ parent.message获取父组件中消息的值。
将值从子组件传递到父组件:父组件通过$children获得子组件实例的数组,然后通过遍历数组,通过实例的名称获得相应的Child1子组件实例,将其赋给child1,然后通过child1.message获得Child1子组件的消息
代码如下:
//子组件
模板
div class=child
h4这是子组件/h4
输入类型=text v-model=message /
收到来自父组件的消息:{{ $parent.message }}/p!-显示父组件实例的消息-
/div
/模板
脚本
导出默认值{
名称:“孩子1”,
data() {
返回{
Message: ,//父组件可以通过这个得到子组件实例的消息。$儿童。
}
},
}
/脚本
//父组件
模板
div class=parent
h3这是父组件/h3
输入类型=text v-model=message /
p收到来自子组件的消息:{{ child1.message }}/p!-消息-显示子组件的实例-
孩子/
/div
/模板
脚本
从导入子级。/孩子
导出默认值{
姓名:家长,
data() {
返回{
消息: ,
孩子1: {},
}
},
组件:{
孩子,
},
已安装(){
this.child1=this。$children.find((child)={
return child . options.name=== child 1 //通过options . name获取对应名称的子实例
})
},
}
/脚本
效果预览
4. $attrs/$listener
简介
$ attrs和$ listeners是Vue2.4中新增加的属性,主要用于用户开发高级组件。
$attrs:用于接收父作用域中不被识别为prop的attribute属性,可以通过v-bind=$attrs 传入内部组件——。这在创建高级组件时非常有用。
想象一下,当你创建一个组件的时候,你要接收几十个参数,比如param1,param2,param3 ……等等。如果你通过道具,那么你需要通过道具声明很多:[param1 , param2 , param3 ,…]等。如果这些道具中的一部分还需要传递给更深层次的子组件,那就比较麻烦了。
使用$attrs,您不需要任何声明。可以通过$attrs.param1,$ attrs.param2直接使用.而且把上面的例子传递给深子组件也很方便。
$listeners:包含父作用域中的v-on事件侦听器。可以通过v-on=$listeners 传入内部组件3354,这对于创建更高级别的组件非常有用。在这里,传递的方法与$attrs非常相似。
代码实例
在这个例子中,有三个组件:A、B和C,它们的关系是:[A [B [C]]],A是B and B的父组件是C的父组件.即一级组件A、二级组件B和三级组件C.我们已经实现了:
向父子传递值:一级组件A通过:messageFromA=message 向二级组件B传递消息属性,二级组件B通过$ attrs.message从A获取一级组件A的消息。
:messageFromA=message
v-bind=$attrs
$attrs.messageFromA
将值传递给子组件和父组件:1级组件A通过@keyup=receive 绑定子组件和孙组件上的keyup事件的监视,2级组件B通过v-on=$listeners 将keyup事件绑定到其输入标记。当二级组件B的输入框被输入时,一级组件A的receive回调将被触发,二级组件B的输入框中的值将被赋给一级组件A的messageFromComp,从而实现值从子到父的传递。
@keyup=receive
CompC v-on=$listeners /
v-on=$listeners
代码如下:
//三级组件C
模板
div class=compc
h5这是C组件/h5
input name= compC type= text v-model= message v-on= $ listeners /!-将组件A keyup的监视回调绑定到输入-
p收到来自组件A的消息:{{ $attrs.messageFromA }}/p
/div
/模板
脚本
导出默认值{
名称: Compc ,
data() {
返回{
消息: ,
}
},
}
/脚本
//二级组件B
模板
div class=compb
h4这是B组件/h4
input name= compB type= text v-model= message v-on= $ listeners /!-将组件A keyup的监视回调绑定到输入-
p收到来自组件A的消息:{{ $attrs.messageFromA }}/p
CompC v-bind= $ attrs v-on= $ listeners /!-继续将组件a keyup的监听回调传递给组件c,继续将组件a传递的attrs传递给组件c-
/div
/模板
脚本
从导入CompC。/compC
导出默认值{
名称: CompB ,
组件:{
CompC,
},
data() {
返回{
消息: ,
}
},
}
/脚本
//一个组件
模板
div class=compa
h3这是组件/h3
输入类型=text v-model=message /
p收到来自{{ comp }}: {{ messageFromComp }}/p的消息
CompB:message froma= message @ keyup= receive /!-侦听后代组件的keyup事件,并将消息传递给后代组件-
/div
/模板
脚本
从导入CompB。/compB
导出默认值{
名称:公司,
data() {
返回{
消息: ,
messageFromComp: ,
组件: ,
}
},
组件:{
CompB,
},
方法:{
Receive(e) {//监听子组件keyup事件的回调,将keyup所在的输入输入框的值赋给messageFromComp。
this.comp=e.target.name
this . messagefromcomp=e . target . value
},
},
}
/脚本
效果预览
5. provide/inject
简介
provide/inject选项需要一起使用,以允许祖先组件将依赖项注入到它的所有后代中,无论组件层次结构有多深,并且只要建立了上下游关系,它就会一直生效。如果是熟悉React的同学,会马上想到Context api,两者非常相似。
Provide:是一个对象,或者是一个返回对象的函数。此对象包含可以注入其子代的属性,即要传递给子代的属性和属性值。
Injcet:字符串数组或对象。当它是一个字符串数组时,它的使用方式与props非常相似,只是接收到的属性从data更改为provide中的属性。当它是一个物体时,它也类似于道具。您可以通过配置属性(如default和from)来设置默认值,并在子组件中使用新的命名属性。
代码实例
本例中有三个组件,一级组件A,二级组件B,三级组件C: [A [B [C]]。a是B and B的父组件,c是它的父组件。该示例实现:
向父子传递值:一级组件A通过provide将消息注入子代和孙代,二级组件B通过inject接收一级组件A的消息:[messageFromA],通过messageFromA.content从一级组件A获取消息的内容属性值
跨级值传递:一级组件A通过provide将消息注入其后代,三级组件C通过inject接收一级组件A中的消息:[messageFromA],通过messageFromA.content获取一级组件A中消息的内容属性值,实现跨级值传递。
代码如下:
//一级组件A
模板
div class=compa
h3这是组件/h3
输入类型= text v-model= message . content /
CompB /
/div
/模板
脚本
从导入CompB。/compB
导出默认值{
名称:公司,
提供(){
返回{
MessageFromA: this.message,//通过provide将消息传递给后代组件。
}
},
data() {
返回{
消息:{
内容: ,
},
}
},
组件:{
CompB,
},
}
/脚本
//二级组件B
模板
div class=compb
h4这是B组件/h4
收到的来自组件a的消息:{ {来自a. content的消息的消息}}/p
CompC /
/div
/模板
脚本
从导入CompC。/compC
导出默认值{
名称: CompB ,
Inject: [messageFromA],//接受提供者在直通注入中传递的消息
组件:{
CompC,
},
}
/脚本
//三级组件C
模板
div class=compc
h5这是C组件/h5
收到的来自组件a的消息:{ {来自a. content的消息的消息}}/p
/div
/模板
脚本
导出默认值{
名称: Compc ,
Inject: [messageFromA],//接受提供者在直通注入中传递的消息
}
/脚本
注意:
有些同学可能想问我,为什么上面的一级组件A中的消息使用对象类型而不是字符串类型,因为vue provide和inject之间的绑定是没有响应的。如果消息是字符串类型,通过一级组件a中的输入输入框改变消息值后不能赋给messageFromA,如果是对象类型,对象属性值改变后messageFromA中的属性值仍然可以改变,后代组件inject接收到的对象属性值也可以相应改变。
子代提供与祖先具有相同的属性,这将在后代中覆盖祖先的提供值。例如,如果2级组件B也通过provide将messageFromA值注入3级组件C,则3级组件C中的messageFromA将首先接收2级组件B注入的值,而不是1级组件A。
效果预览
6. eventBus
简介
EventBus也叫事件总线,注册一个新的Vue实例,通过调用这个实例的$ emit和$ on来监控和触发这个实例的事件,通过传入参数来实现组件的全局通信。它是一个没有DOM的组件,有些只是实例化方法,所以很轻。
我们可以通过以下方式在全球Vue实例上注册:
//main.js
Vue.prototype.$Bus=new Vue()
但是当项目太大的时候,我们最好把事件总线抽象成一个文件,导入到每个需要使用的组件文件中。这样,就不会污染全局命名空间:
//bus.js,使用时通过导入引入。
从“vue”导入Vue
export const Bus=new Vue()
原理分析
事实上,eventBus的原理相当简单,即使用订阅-发布模式并实现$ emit和$ on:
//eventBus原理
导出默认类别总线{
构造函数(){
this.callbacks={}
}
$on(事件,fn) {
this . callbacks[event]=this . callbacks[event] []
this . callbacks[事件]。推动(fn)
}
$emit(event,args) {
这个。回调[事件]。forEach((fn)={
fn(参数)
})
}
}
//在主页。射流研究…中引入以下
//Vue.prototype.$bus=new Bus()
代码实例
在这个实例中,共包含了四个组件:[ A [ B [ C、D ] ],1级组件答,2级组件b,3级组件C和3级组件d。我们通过使用事件总线实现了:
全局通信:即包括了父子组件相互通信、兄弟组件相互通信、跨级组件相互通信。4个组件的操作逻辑相同,都是在投入输入框时,通过这个。$巴士emit(sendMessage ,obj)触发发送消息事件回调,将发报机和消息封装成对象作为参数传入;同时通过这个。$巴士在( sendMessage ,obj)上监听其他组件的发送消息事件,实例当前组件示例发报机和消息的值。这样任一组件投入输入框值改变时,其他组件都能接收到相应的信息,实现全局通信。
代码如下:
//main.js
Vue.prototype.$bus=new Vue()
//1级组件A
模板
div class=containerA
氘这是CompA/h2
input type= text v-model= message @ keyup= sendMessage /
p v-show=messageFromBus sender!==$options.name
收到{{发件人}}的消息:{{ messageFromBus }}
/p
CompB /
/div
/模板
脚本
从导入CompB ./compB
导出默认值{
名称:公司,
组件:{
CompB,
},
data() {
返回{
消息: ,
messageFromBus: ,
发件人: ,
}
},
已安装(){
这个。$巴士on(sendMessage ,(obj)={ //通过事件总线监听发送消息事件
const { sender,message }=obj
this.sender=发送者
this.messageFromBus=message
})
},
方法:{
sendMessage() {
这个。$巴士发出( sendMessage ,{ //通过事件总线触发发送消息事件
发件人:这个. options.name,
消息:this.message,
})
},
},
}
/脚本
//2级组件B
模板
div class=集装箱船
h3这是CompB/h3
input type= text v-model= message @ keyup= sendMessage /
p v-show=messageFromBus sender!==$options.name
收到{{发件人}}的消息:{{ messageFromBus }}
/p
CompC /
CompD /
/div
/模板
脚本
从导入CompC ./compC
从导入CompD ./compD
导出默认值{
名称: CompB ,
组件:{
CompC,
CompD,
},
data() {
返回{
消息: ,
messageFromBus: ,
发件人: ,
}
},
已安装(){
这个。$巴士on(sendMessage ,(obj)={ //通过事件总线监听发送消息事件
const { sender,message }=obj
this.sender=发送者
this.messageFromBus=message
})
},
方法:{
sendMessage() {
这个。$巴士发出( sendMessage ,{ //通过事件总线触发发送消息事件
发件人:这个. options.name,
消息:this.message,
})
},
},
}
/脚本
//3级组件C
模板
div class=containerC
p这是CompC/p
input type= text v-model= message @ keyup= sendMessage /
p v-show=messageFromBus sender!==$options.name
收到{{发件人}}的消息:{{ messageFromBus }}
/p
/div
/模板
脚本
导出默认值{
名称: CompC ,
data() {
返回{
消息: ,
messageFromBus: ,
发件人: ,
}
},
已安装(){
这个。$巴士on(sendMessage ,(obj)={ //通过事件总线监听发送消息事件
const { sender,message }=obj
this.sender=发送者
this.messageFromBus=message
})
},
方法:{
sendMessage() {
这个。$巴士发出( sendMessage ,{ //通过事件总线触发发送消息事件
发件人:这个. options.name,
消息:this.message,
})
},
},
}
/脚本
//3级组件D
模板
div class=containerD
p这是CompD/p
input type= text v-model= message @ keyup= sendMessage /
p v-show=messageFromBus sender!==$options.name
收到了{{ sender }}: {{ messageFromBus }}的邮件
/p
/div
/模板
脚本
导出默认值{
名称: CompD ,
data() {
返回{
消息: ,
messageFromBus: ,
发件人: ,
}
},
已安装(){
这个。$巴士。$ on (sendMessage ,(obj)={//通过eventBus侦听sendMessage事件
const { sender,message }=obj
this.sender=发送者
this.messageFromBus=message
})
},
方法:{
sendMessage() {
这个。$巴士。$ emit (sendMessage ,{//通过eventBus触发sendMessage事件
发件人:这个。$options.name,
消息:this.message,
})
},
},
}
/脚本
效果预览
图片太大,截图处理
7. Vuex
当项目庞大,多人维护同一个项目时,如果使用事件总线进行全局通信,很容易使全局变量的变化变得不可预测。于是就有了Vuex的诞生。
Vuex是专门为Vue.js应用开发的状态管理模式。它采用集中存储来管理应用程序所有组件的状态,并确保状态以可预测的方式随相应的规则变化。
关于Vuex的内容,请参考Vuex的官方文档[1],这里就不尝试班门弄斧了,只看代码。
代码实例
Vuex的实例和事件总线leisi也包含四个组件:[A [B [C,D]]]一级组件A、二级组件B、三级组件C和三级组件D .我们在这个例子中实现了:
全局通信:代码内容类似于eventBus,但使用起来比eventBus方便得多。每个组件通过watch监控输入输入框的变化,通过vuex的提交触发突变,从而改变stroe的值。然后各个组件通过计算动态获取存储中的数据,从而实现全局通信。
//store.js
从“vue”导入Vue
从“vuex”导入Vuex
Vue.use(Vuex)
导出默认的新Vuex。商店({
状态:{
消息:{
发件人: ,
内容: ,
},
},
突变:{
sendMessage(state,obj) {
state.message={
发件人:obj.sender,
内容:obj.content,
}
},
},
})
//组件a
模板
div class=containerA
h2这是CompA/h2
输入类型=text v-model=message /
p v-show= message from store sender!==$options.name
收到来自{ { sender } }:{ { messageFromStore } }的消息
/p
CompB /
/div
/模板
脚本
从导入CompB。/compB
导出默认值{
名称:公司,
组件:{
CompB,
},
data() {
返回{
消息: ,
}
},
计算值:{
messageFromStore() {
归还这个。$store.state.message.content
},
发件人(){
归还这个。$store.state.message.sender
},
},
观察:{
消息(新值){
这个。$store.commit(sendMessage ,{
发件人:这个。$options.name,
内容:newValue,
})
},
},
}
/脚本
与eventBus中一样,除了引入子组件之外,组件B、C和D中的代码是相同的,因此不再赘述。
效果预览
总结
7中Vue组件的通信方式如上所述,它们可以进行的通信类型如下图所示:
Props/$emit:可以实现父子组件的双向通信,一般是我们日常父子组件通信中最常用的选择。
V-slot:可以实现父子组件之间的单向通信(从父组件向子组件传递值)。实现可复用组件时,将DOM节点、html等内容转移到组件中,对一些组件库的表值进行二次处理等。v槽可以优先。
$ refs/$ parent/$ children/$ r oot:可以实现父子组件之间的双向通信,其中$ r oot可以实现从根组件实例到其后代的单向值传递。当父组件不传递值或通过v-on绑定监听时,父子如果想获取对方的属性或方法,可以考虑使用这些API。
$ attrs/$ listeners:它可以实现跨级双向通信,它允许您简单地获取传入的属性和绑定监控,并且可以方便地传递给下属子组件。这在构建高级组件时非常有用。
提供/注入:可以实现跨级单向通信,轻注入依赖到子代和孙代组件中。当实现高级组件和创建组件库时,这是您的最佳选择。
EventBus:可以实现全局通信,在项目规模不大的情况下,可以用来实现全局事件监控。但是,应该谨慎使用eventBus,以避免全局污染和内存泄漏。
Vue:可以实现全球沟通,这是VUE项目全球状态管理的最佳实践。当项目很大,你想集中管理全局组件的状态时,安装Vuex是对的!
也就是说,彻底理解了Vue组件的七种通信模式的细节。更多关于Vue组件通信方式的信息,请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。