Vue入门——组件间通信

201 阅读2分钟

组件

Vue组件之间的关系大致可以分为父子组件和非父子组件,非父子组件又可以分成兄弟组件跨级组件

通信方式

vue中的通信方式分为以下7种

  1. prop/$emit
  2. v-slot:(单向),实现可复用组件,传Dom、html等可以考虑
  3. $refs/$parent/$children/$root
  4. $attrs/$listener (双向跨级)
  5. provide/inject
  6. eventBus (存在内存泄漏问题)
  7. Vuex (全局通信)

不同的通信方式适用于不同关系的组件之间

  • 父子组件间通信:1,2,3,4,5,6,7(果然还得是父子组件)
  • 兄弟组件:6,7
  • 跨级组件:4,5,6,7

prop/$emit

prop/$emit可以说是父子组件间通信用得最多的了。

  • 父组件 -> 子组件:通过prop

    父组件引入子组件并传入参数

    <my-child :title="title" ><my-child>
    

    子组件接收prop

    props:{
      title:{
        type:String,
        default:'标题',
      }
    }
    
  • 子组件 -> 父组件:$emit

    子组件通过$emit向上传参数

    <button @click="emitData">向父组件传参</button>
    
    emitData(){
      this.$emit('fromChild','子组件传的参数')
    }
    

    父组件接收子组件传来的参数

    <my-child :title="title" @fromChild="receive"><my-child>
    
    receive(data){
      console.log(data)
    }
    

v-slot

插槽又分为具名插槽和默认插槽

默认插槽

//父组件
<my-child :title="title" @fromChild="receive">
  <div>默认插槽</div>
<my-child>

//子组件
<div>
    ...
    <slot></slot>
    ...
</div>

具名插槽

注:具名插槽需要包在template里面,要不然会报错

//父组件
<my-child>
  <template v-slot:mySlot> // v-slot: + 插槽名
    ···
  </template>
</my-child>


//子组件
<div>
  <slot name="mySlot"></slot> // name="插槽名"
</div>

以具名插槽为例v-slot传参

//父组件
<testChild>
   <template v-slot:mySlot="slotData">//具名插槽,v-slot: +插槽名+ ="自定义数据名",子组件所传参数都是其属性
    {{slotData.name}}
   </template>
</testChild>

//子组件
<div>
  ...
  <slot name="test" :name="name"></slot>
  ...
</div>

$refs/$parent/$children/$root

$refs:可以将$refs绑定在子组件上,从而获取子组件的实例。

$parens :直接通过this.$parent来获取当前组件的父组件实例。

$children : 同样也可以直接通过this.$children来获取当前组件的子组件实例。

注意:this.$children数组中的元素下标并不一定对用父组件引用的子组件的顺序。所以在使用时需要根据一定的条件例如子组件的name去找相应的子组件。

$root: 当前组件树的根Vue实例。如果当前实例没有父实例,此实例就是自己。通过$root,可以实现组件之间的跨级通信。

$attrs/$listener

$attrs可以获取父组件传递过来的所有属性,不包含class,style和props中接收的

当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ,并且可以通过 v-bind="$attrs" 传入内部组件,在创建高级别的组件时非常有用

使用$attrs的好处

  • 在子组件中不用再通过props来接收来自父组件的信息
  • 在子组件中调用孙子组件,绑定$attrs,孙子组件就可以直接接收父组件的内容
  • 多层传递省时省力

$listeners,它是一个对象,里面包含了作用在这个组件上的所有监听器。

$listeners的作用很明显,就是在高层组件向低层组件传参使用$attrs一样,低层组件向高层组件传递数据用$listeners即可。解构后,和正常函数一样调用。

provide/inject

provide/inject使用方法很简单,父组件(或者说高层组件)通过provide提供数据,其他组价可以使用inject注入数据。

平时开发并不推荐使用provide/inject,开发组件库,插件库除外,写的位置与data同级

//父组件
provide() { 
  return { 
    parent: "这是父组件的provide" 
  }; 
}

//子组件

inject: 
{
  parent: { 
    default: () => ({}) 
  } 
},

eventBus

有时候关系复杂的组件之间需要通信,那么之前提到的方法就会变得很复杂,所以就需要有个事件总线来进行通信(就很像接线员把需要通信的双方连接起来)

可以定义一个全局的eventBus,当然如果用得不多也可以定义eventBus然后局部引用,这里以全局为例

//main.js
window.eventBus = new Vue();  //可以挂在window下也可以挂在Vue.prototype下

//触发事件
EventBus.$emit('eventName', param1,param2,...)

//监听事件
EventBus.$on('eventName', (param1,param2,...)=>{
    ...
})
//移除事件
EventBus.$off('eventName');

注:页面销毁的时候请养成移除事件的好习惯

Vuex

Vuex若要详细说可能会有很多内容,那就放在下次的文章里单独说