vue组件组件通信方式和插槽

790 阅读1分钟

一.组件通信常用方式

  1. props
  2. $emit/on
  3. event bus
 // 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', (data) => console.log(data)) // console 123
// child2
this.$bus.$emit('foo','123')
  1. vuex
  2. $parent/root
// $parent/$root
//兄弟组件之间通信可通过共同祖辈搭桥,$parent$root。
// brother1
this.$parent.$on('foo', (data) => console.log(data)) // console 123
// brother2
this.$parent.$emit('foo','123')
  1. $children
// $children
// 父组件可以通过$children访问子组件实现父子通信。
// parent
this.$children[0].xx = 'xxx'
 //注意:$children不能保证子元素顺序(如果存在异步组件,位置就不一定对,或者有v-if,,动态组件等)
  1. $refs
// $refs
// 获取子节点引用
// parent
<HelloWorld ref="hw"/>
mounted() {
  this.$refs.hw.xx = 'xxx'
}
//注意:$ref$children的区别,,ref可以是元素,children只能是子组件
  1. provide/inject
// provide/inject
// 能够实现祖先和后代之间传值,不是响应式的
// ancestor
provide() {
    return {foo: 'foo'}
}
// descendant
inject: ['foo']

provide实现响应可以通过一下2种方法

//1.provide提供祖先组件的实例
provide(){
    return {
        theme: this
    }
}
//2.使用2.6最新API,vue.observable优化响应式provide
provide() {
    this.theme = vue.observable({
        color: 'blue'
    })
}
  1. 非props属性($attrs/listener)
// $attrs/$listeners
// 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。当一个组件没有 声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外),并且可以通过 v-bind="$attrs" v-on="$listeners" 传入内部组件——在创建高级别的组件时非常有用。
// child:并未在props中声明foo 
<p>{{$attrs.foo}}</p>
// parent
<HelloWorld foo="foo"/>

二.vue组件插槽

  1. 匿名插槽(将内容全部插入子组件slot里面)
// 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>
  1. 作用域插槽(分发内容要用到子组件中的数据)
// comp3
<div>
  <slot :foo="foo"></slot>
</div>
// parent
<Comp3>
<!-- 把v-slot的值指定为作用域上下文对象 --> 
<template v-slot:default="slotProps"> 来自子组件数据:{{slotProps.foo}}</template>
</Comp3>