组件间通讯

297 阅读1分钟

组件通信常用方式

  1. props
  2. emit/emit/on
  3. event
  4. bus
  5. vuex
  6. $refs

用的较少的方式

  1. $parent
  2. $children
  3. $root
  4. provide/inject
  5. ⾮prop特性
    • $attrs
    • $listeners

$parent/$root

兄弟组件之间通信可通过共同祖辈搭桥,parentparent或root

// brother1 
this.$parent.$on('foo', handle) 
// brother2 
this.$parent.$emit('foo')

$children

⽗组件可以通过$children访问⼦组件实现⽗⼦通信。

// parent 
this.$children[0].xx = 'xxx'

注意:$children不能保证⼦元素顺序

$attrs"/$listeners 属性与事件

包含了⽗作⽤域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当⼀个组件没有 声明任何 prop 时,这⾥会包含所有⽗作⽤域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传⼊内部组件——在创建⾼级别的组件时⾮常有⽤。

// child:并未在props中声明foo 
<p>{{$attrs.foo}}</p>
 
// parent 
<HelloWorld foo="foo"/>
// 父组件中件引用child2组件 给Grandson隔代传值
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2>
 
// child2组件中引用grandson组件 Child2做展开 
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson>
 
// grandson组件 Grandson使⽤ 
<div @click="$emit('some-event', 'msg from grandson')">    {{msg}} </div>

provide/inject

// componeA
export default {
    provide(){
        return {
            foo:'bus'//将'bus' 改为this,可将数据变为响应式
        }
    }
}

//componeB
<template>
<div>
    {{foo}}
</div>
</template>
export default {
    inject:['foo']//该数据非响应式,父组件一次性注入该字段数据,若想要该字段响应式,需父组件传this引用类型数据过来;
}

事件总线

// Bus:事件派发、监听和回调管理 
class Bus {  
    constructor(){    
        this.callbacks = {}  
    }  
    $on(name, fn){    
        this.callbacks[name] = this.callbacks[name] || []
        this.callbacks[name].push(fn)  
    }  
    $emit(name, args){    
        if(this.callbacks[name]){      
            this.callbacks[name].forEach(cb => cb(args))    
        }  
    } 
}
 
 使用方式
// main.js 
Vue.prototype.$bus = new Bus()
// child1 
this.$bus.$on('foo', handle) 
// child2 
this.$bus.$emit('foo')
实践中通常⽤Vue代替Bus,因为Vue已经实现了$on和$emit

插槽

插槽语法是Vue 实现的内容分发 API,⽤于复合组件开发。该技术在通⽤组件库开发中有⼤量应⽤。

  1. 匿名插槽
// comp1 
<div>  
    <slot></slot> 
</div>
 
// parent 
<comp>hello</comp>

  1. 具名插槽:将内容分发到⼦组件指定位置
// comp2 
<div> 
    <slot></slot>  
    <slot name="content"></slot> 
</div>
 
// parent 
<Comp2>    
<!-- 默认插槽⽤default做参数 -->    
<template v-slot:default>具名插槽</template>    
<!-- 具名插槽⽤插槽名做参数 -->    
<template v-slot:content>内容...</template> 
</Comp2>

3.作⽤域插槽:分发内容要⽤到⼦组件中的数据

// comp3 
<div>  
<slot :foo="foo"></slot> 
</div>
 
// parent 
<Comp3>    
    <!-- 把v-slot的值指定为作⽤域上下⽂对象 -->    
    <template v-slot:default="slotProps"> 
    来⾃⼦组件数据:{{slotProps.foo}}
    </template>
</Comp3>