前言
大家对vue组件通信的方式应该都有了解,下面我来说下自己知道的通信方式
- props
- $emit 触发自定义事件
- v-model 双向绑定
- $refs
- c h i l d r e n / children/ children/parent
- $root
- a t t r s / attrs/ attrs/listeners
- slot插槽
- provide/inject
- EventBus
- Vuex
props
最常见的组件通信方式了,常用于父子间通信.
注意: 因为vue中数据是单向向下流动的,所以不要在子组件中直接修改props传递下去的数据
父组件
<template>
<div class="father">
<button @click="changeMsg">修改信息</button>
<SonComponent :msg="msg"/>
</div>
</template>
// script
data(){
return{
msg:''
}
},
methods:{
changeMsg(){
this.msg='我是父组件props传过来的数据';
}
}
子组件
子组件接收的话有两种方式, 可以写数组或者对象
<template>
<div>
我是props数据: {{ msg }}
</div>
</template>
// script
props:['msg'],
// props:{
// msg:{
// type: String, // props传递的数据类型
// default: '默认信息', // 默认值
// require: true, // 必传
// validate: /\*/ // 校验规则
// }
// },
效果
$emit
一般用于父组件传递事件给子组件,子组件通过$emit进行触发
父组件
<template>
<div class="father">
<SonComponent :msg="msg" @changeMsg="changeMsg"/>
</div>
</template>
// script
methods:{
changeMsg(msg){
msg=msg??'我是父组件props传过来的数据';
this.msg=msg;
}
}
子组件
<div>
<button @click="$emit('changeMsg','emit修改的数据')">emit修改</button>
我是props数据: {{ msg }}
</div>
效果
v-model
首先我们需要知道,v-model的话是v-on以及v-bind的语法糖,一般我们用于双向绑定在input
上,但是我们也可以用其对父子组件进行通信。
vue2 vue3有点区别,可以去看看官方文档 V2官方文档
V3官方文档
我用的是V2的,需要在写model
配置项
父组件
<div class="father">
<SonComponent v-model="msg"/>
</div>
子组件
<div>
<button @click="$emit('modelChange','model修改的数据')">model修改</button>
我是props数据: {{ newMsg }}
</div>
// script
model:{
prop:'newMsg', //父组件传来的值选择用 名为newMsg 的prop来接收,所以必须下面的props必须要写,且对应
event:'modelChange' //自定义父组件传递过来的事件名,通过emit触发时,第二个参数为父组件model绑定数据的新值
},
props:['newMsg'],
效果
$refs
我们通常会将 $refs
绑定在DOM元素上,来获取DOM元素的 attributes
。在实现组件通信上,我们也可以将 $refs
绑定在子组件上,从而获取子组件实例。
ref
被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs
对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素; 如果用在子组件上,引用就指向组件实例。
父组件
<div class="father">
<button @click="changeMsg">修改信息</button>
<SonComponent ref="son"/>
{{ msg }}
</div>
// script
methods:{
changeMsg(){
console.log(this.$refs.son)
this.msg=this.$refs.son.sonMsg;
}
}
子组件
data() {
return {
sonMsg:'我是son中的数据'
};
},
效果
通过$refs
访问组件得到的是组件实例
c h i l d r e n / children/ children/parent
我们可以在 Vue 中直接通过this.$parent
来获取当前组件的父组件实例(如果有的话),通过this.$children[index]
获取对应的子组件实例
父组件
<div class="father">
<button @click="changeMsg">修改信息</button>
<SonComponent/>
{{ msg }}
</div>
// script
methods:{
changeMsg(){
console.log(this.$children) // 获取的是子组件数组,需要通过索引值访问具体的子组件
this.$children[0].changeSonMsg('Father给你的数据')
}
}
子组件
<div>
son的sonMsg:{{sonMsg}}
<br/>
parent的msg:{{parMsg}}
</div>
// script
data() {
return {
sonMsg:'我是son中的数据',
parMsg:this.$parent.msg
};
},
methods: {
changeSonMsg(msg){
this.sonMsg=msg;
}
},
效果
$children获取的子组件是数组,需要用索引获取具体的实例
$parent获取父组件只有一个
$root
获取当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。通过 $root ,我们可以实现组件之间的跨级通信。
通过this.$root
获取根实例,注意不是App.vue
a t t r s / attrs/ attrs/listeners
a t t r s :包含了父作用域中不被认为 ( 且不预期为 ) p r o p s 的特性绑定 ( ‘ c l a s s ‘ 和 ‘ s t y l e ‘ 除外 ) 。当一个组件没有声明任何 p r o p s 时,这里会包含所有父作用域的绑定 ( ‘ c l a s s ‘ 和 ‘ s t y l e ‘ 除外 ) ,并且可以通过 ‘ v − b i n d = " attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (`class` 和 `style` 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (`class` 和 `style` 除外),并且可以通过 `v-bind=" attrs:包含了父作用域中不被认为(且不预期为)props的特性绑定(‘class‘和‘style‘除外)。当一个组件没有声明任何props时,这里会包含所有父作用域的绑定(‘class‘和‘style‘除外),并且可以通过‘v−bind="attrs"` 传入内部组件
l i s t e n e r s :包括父作用域中的 ‘ v − o n ‘ 事件监听器(但不包括添加了 ‘ . n a t i v e ‘ 修饰器的那些事件监听器)。可以通过 ‘ v − o n = " listeners:包括父作用域中的 `v-on` 事件监听器(但不包括添加了 `.native` 修饰器的那些事件监听器)。可以通过 `v-on=" listeners:包括父作用域中的‘v−on‘事件监听器(但不包括添加了‘.native‘修饰器的那些事件监听器)。可以通过‘v−on="listeners"`,将这些事件监听器向下传入到组件内部
父组件
<SonComponent @changeInfo="changeInfo" :info="info" :msg="msg"/>
// script
data(){
return{
msg:'默认值',
info:'哈哈哈哈'
}
},
methods:{
changeInfo(info){
this.info=info
},
}
子组件
<p>子组件的$attrs: {{ $attrs.info }}</p> //子组件可以通过$attr直接获取到父组件传递下来的数据
<GrandSon v-bind="$attrs" v-on="$listeners"/> //给孙子组件传递$attrs,不能用props接收需要传递下去的数据,不需要传递的可以接收
// script
props:['msg'] //接收msg, 那么传递给下级组件的$attrs中就没有msg了
孙子组件
触发$listeners
传递下来的事件就和触发自定义事件一样 用$emit
孙子的$attrs
没有值是因为info
被自己接收了、msg
被上一级组件接收了
<div>
<button @click="$emit('changeInfo','孙子组件的传值')">修改爷爷的info</button>
<p>孙子的props:{{info}}</p>
<p>孙子的$attrs:{{$attrs}}</p>
</div>
// script
props:{
info:{
type:String,
default:'孙子的默认值'
}
},
效果
slot插槽
- 匿名插槽(父->子)
子组件定义了solt,但未提供名字,这就是匿名插槽,也叫做默认插槽,只要出现的父组件中,未指定插槽名字的内容,都会默认放到匿名插槽里。
- 具名插槽(父->子)
所谓具名插槽,就是给插槽命了名字,父组件放进来的内容,需要指定插槽的名称,这个时候才会被分发到这个具名插槽中。
- 作用域插槽(子->父)
有时让插槽内容能够访问子组件中才有的数据是很有用的。所以提供了作用域插槽
父组件
<SonComponent>
{/* defaultObj 上获得的值是匿名插槽中 v-bind 绑定的所有值的对象 */}
<template v-slot:default="defaultObj">
<div>
{{ defaultObj }}
<p>{{defaultObj.defaultMsg}}</p>
</div>
</template>
{/* 直接将nameMsg解构出来 */}
<template v-slot:name="{nameMsg}">
<div>
{{ nameMsg }}
<p>{{`父组件传递的信息${info}`}}</p>
</div>
</template>
</SonComponent>
// script
data(){
return{
info:'哈哈哈哈'
}
},
子组件
<slot :defaultMsg="defaultMsg"></slot>
<slot name="name" :nameMsg="nameMsg"></slot>
// script
data() {
return {
defaultMsg:'匿名插槽中使用作用域插槽',
nameMsg:'具名插槽中使用作用域插槽'
};
},
效果
provide/inject
**provide:**是一个对象,或者是一个返回对象的函数。该对象包含可注入其子孙的 property ,即要传递给子孙的属性和属性值。
**injcet:**一个字符串数组,或者是一个对象。当其为字符串数组时,使用方式和props十分相似,只不过接收的属性由data变成了provide中的属性。当其为对象时,也和props类似,可以通过配置default和from等属性来设置默认值,在子组件中使用新的命名属性等。
:::tip
注意:provide
和 inject
绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象(引用类型),那么其对象的属性还是可响应的
:::
// 爷爷组件
<button @click="changeMsg('修改后的msg')">修改msg</button>
<p>爷爷的info:{{info}}</p>
<p>爷爷的msg:{{msg}}</p>
<SonComponent/>
<button @click="changeInfo('修改后的info')">修改info</button>
provide(){
return{
msg:this.msg,
info:this.info
}
},
data(){
return{
msg:'默认值',
info:{msg:'哈哈哈哈'}
}
},
methods:{
changeInfo(info){
this.info.msg=info
},
changeMsg(msg){
this.msg=msg;
}
}
// 孙子组件
<p>孙子收到的msg:{{ msg }}</p>
<p>孙子收到的info:{{ info.msg }}</p>
inject:['info','msg'],
效果
EventBus 事件总线
eventBus又称事件总线,通过注册一个新的Vue实例,通过调用这个实例的
e
m
i
t
和
emit和
emit和on等来监听和触发这个实例的事件,通过传入参数从而实现组件的全局通信。它是一个不具备 DOM 的组件,有的仅仅只是它实例方法而已,因此非常的轻便。
我们可以通过在全局Vue实例上注册:
// main.js 文件中
Vue.prototype.$Bus = new Vue()
// 爷爷组件
<p>爷爷的msg:{{msg}}</p>
<SonComponent/>
data(){
return{
msg:'默认值'
}
},
created(){
this.$Bus.$on('changeMsg',this.changeMsg)
},
beforeDestroy(){
this.$Bus.$off('changeMsg') //组件销毁前 解绑事件
},
methods:{
changeMsg(msg){
this.msg=msg;
}
}
// 孙子组件
<button @click="$Bus.$emit('changeMsg','孙子组件触发了changeMsg事件')">触发爷爷组件上的事件</button>
vuex 大家可以直接去看看,挺多的