目录
一、props与$emit
二、ref/$ref
三、eventBus
四、provide与inject
五、$children与$parent
六、$attrs / $listeners
前言 : 组件作为vue最强大的功能之一,但每个组件实例模块却是彼此独立的,这就意味着他们之间无法直接的进行引用,这时候,它们之间的通讯就变得十分重要了。
一、props与$emit
props是子组件中的一个属性,可以是数组也可以是对象,是对象时会对接收数据进行判断操作。其只能用于接收父组件中传入的数据,如果想向父组件中传递数据,需要使用$emit方式并向里面加入对应参数,父组件使用v-on方式进行相互绑定即可。
父组件的传入数据方式与接收子组件传回数据方式
其中 :parHandData 为自定义的名字,子组件的props与其对应即可,list为data中定义好的数据
使用v-on绑定子组件$emit写入的自定义事件
// 父组件中
<template>
<div id="app">
// 使用子组件
<son-module :parHandData="list" v-on:binding="dinMetcik"></son-module> // 将数据传递给子组件
</div>
</template>
<script>
// 引入子组件
import sonModule from ./sonModule.vue
export default {
name: "father",
components: sonModule // 注册子组件
data() {
return {
list: [
{id:1,name:"imac",price:1},
{id:2,name:"ipad",price:2},
{id:3,name:"iphone",price:3}
]
}
},
methods: {
// 通过绑定触发的一个事件,接收到的参数为子组件中$emit传入的两个参数
dinMetcik(sonParamaO,sonParamaT){
sonParamaO.price = sonParamaT;
}
}
}
</script>
子组件的接收
注意:接收的数据外面需要嵌套引号,如需使用,直接this.:parHandData即可
如需传回父组件,使用$emit内写入相应参数
// 子组件中
export default {
name: son,
props: ["parHondData"], // 接收到父组件传递的数据
mounted(){
console.log(this.parHondData); // 挂载后显示一下
// 传入父组件的参数,第一个为自定义事件,后两个为参数
this.$emit("binding",this.parHondData[2],this.parHondData[2].price+1);
}
};
当然,子传父的$emit方法有3种传递方式,还有syan指令配合updata绑定和model属性操作方式。props作为最传统的通信方式,正常父子通信轻松实现,其实很多场景下的通信也都能够实现,但是可能要有很多个props与$emit来回嵌套,所有有必要出现更方便多样的通信方式。
二、ref/$ref方式
父组件中对子组件数据进行操作
ref使用在子组件中,相当于为父组件中使用注册的子组件绑定一个标识,标识到的子组件会存在与父组件中的this.$ref,这里面包含了标识过的子组件的基本所有信息 。
// 父标签中
<template>
<son ref="child"></son>
</template>
<script>
export default {
name: "father",
data() {
return {
hondChild: "传入子元素的数据"
}
},
mounted(){
console.log(this.$ref.child); // 打印的为整个子组件中的内容
// 如果需要对子组件中的值进行改变,可直接在父组件中进行操作
this.$ref.child.hondPar = this.hondChild;
}
}
</script>
子组件中
在子组件中查找父组件,只需其使用this.$parent即可查到父组件中的所有内容
this.$parent,顾名思义,就是当前组件父亲,即父组件。如果查找爷爷的话,则是this.$parent.$parent
如果想要传递,则可以效仿上面父组件中操作子组件的方式
<script>
export default {
name: "son",
data(){
return {
hodePar: ""
}
},
mounted(){
// 在父组件中已找到子组件内容并将其修改
console.log(this.hodePar); // 传入子元素的数据
}
};
</script>
三、eventBus
eventBus事件总线适用于父子组件、非父子组件等之间的通信。
使用eventBus方式的话,则需要在外部建立一个js文件,里面注入相应代码后,即可作为组件的事件管理中心,类似于代理人。
注入代码如下:
// 因为需要使用vue,所以引入vue
import Vue from "vue"
// 创建一个相互传递中间的代理人
export const EventBus = new Vue();
在事件管理中心创建好后,要进行传递数据的组件需要在内部引入以上创建的js代码进行使用
以下假设有两个需要传递数据的兄弟组件BrotherGe和BrotherDi
弟弟向哥哥传递方式如下
<script>
// 需要属于代理人进行传递,所以需要引入代理人
import {EventBus} from './EventBus.js'
export default{
name: "BrotherDi",
data(){
return {
Di_date: "传给哥哥的数据"
}
},
mounted(){
// 自定义一个标识并写入要传递的数据发送给哥哥
EventBus.$emit("assd",{val:this.Di_date});
}
}
</script>
哥哥接收的方式如下
<script>
import {EventBus} from '../EventBus.js'
export default{
name: "BrotherGe",
data(){
return {
Ge_date: ""
}
},
mounted(){
// 哥哥使用$on监听到弟弟发送到的,并使用内部数据进行接收
EventBus.$on("assd",({v}) => {this.Ge_date = v});
console.log(this.Ge_date); // 传给哥哥的数据
}
}
</script>
四、provide/inject
注入/依赖(provide/inject)通信方法,用于处理父子组件、爷孙组件、亦或者隔代许多的组件都相对方便,层数再深也好处理,一步解决,不用一层一层去传递数据了。且相互传递的两个组件是相互绑定的,也就是说,在子组件中改变其数据时也会影响父组件的。
provide与inject是vue提供的两个钩子,和data、methods等同级,其中provide与data写法相似,都是一个函数,通过return返回出要传递的数据。而inject类似于props,可以是数组也可以是对象,能接收到provide传入的数据。
provide传递方式如下
<script>
export default{
name: "parProvide",
data(){
return {
proCs: "provide传给子代的"
}
},
provide(){
return {
proCs: this.proCs // 参数名为自定义,参数值为当前组件里的内容
}
}
}
</script>
inject接收方式如下
<script>
export default {
name: "sonInject",
// 接收父组件通过Provide属性传入的数据
inject: ["proCs"], // 如果修改proCs的数据,父组件也会相应改变的
mounted(){
console.log(this.proCs); // provide传给子代的
}
}
</script>
五、$children与$parent
听其名,闻其意。$children可以在父组件中直接访问到子组件的实例,而$parent可以在子组件中访问到父组件的实例,基本包含到了所有信息。这里需要注意以下,因为父组件会有多个子组件,而子组件只能有一个父组件,所以当在父组件中使用this.$children时访问到的会是一个数组,这个数组中包含着所有的子组件,即this.$children[index]来访问用到的子组件。相反,子组件访问父组件则不需要。
这种方式可以直接访问到数据,不需要刻意的代码去传递参数。
父组件中访问子组件
<script>
import children from './children.vue'
export default{
name: "father",
conponents: {
children
}
data(){
return {
fatherTest: "父组件中的内容"
}
},
mounted(){
// 访问到子组件中的内容
console.log(this.$children[0]); // 子组件中的内容
{
}
</script>
子组件中访问父组件
<script>
import children from './children.vue'
export default{
name: "children",
conponents: {
children
}
data(){
return {
sonTest: "子组件中的内容"
}
},
mounted(){
// 访问到父组件中的内容
console.log(this.$parent.fatherTest); // 父组件中的内容
{
}
</script>
六、$attrs / $listeners
如果是用props/ $emit 来一级一级的传递,确实可以完成,但是比较复杂;如果使用事件总线,在多人开发或者项目较大的时候,维护起来很麻烦;如果使用vuex,如果仅仅是传递数据,那可能有点浪费了。
针对上述情况,vue引入了 $attrs / $listeners,实组件之间的跨代通信。
$attrs:继承所有的父组件属性(除了props传递的属性、class 和 style),一般用在子组件的子元素上 $listeners:该属性是一个对象,里面包含了作用在这个组件上的所有监听器,可以配合 v-on=" $listeners " 将所有的事件监听器指向这个组件的某个特定的子元素。(相当于子组件继承父组件的事件) 再说一下 inheritAttrs
默认值为true,继承所有的父组件属性除props之外的所有属性。 只继承class属性。 $attrs / $listeners的用法: A组件(APP.vue):
B组件(Child1.vue):
C 组件 (Child2.vue):
在上述代码中:
C组件中能直接触发test的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性 在B组件中通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) 总结 根据以上对这6种组件间的通信方法,可以将不同组件间的通信分为3种类型:父子组件间通信、兄弟组件间通信、任意组件间通信
希望能够有所帮助!