Vue2组件通信 - dispatch 和 broadcast

承接文章 Vue2中10种组件通信方式和实践技巧,因为一篇文章太长无法发表,所以做拆分。

8,dispatch 和 broadcast

在 Vue@1 版本中,有 $dispatch$broadcast 这种基于组件树的工作流来通信。缺点是项目变复杂后,结构扩展的过程中会变得越来越难维护,所以被废弃了。

整体思路

本质上还是 $on()$emit() 监听和触发事件。

关键点:$emit() 触发的是实例自己通过 $on() 监听的事件。

1,dispatch 是向任意指定的祖先组件通信。

实现思路:先在指定的祖先组件中使用 this.$on() 监听事件 eventParent。后代组件需要触发祖先组件监听的事件 eventParent 时,层层向上找到指定的祖先组件,通过 $emit() 触发监听的事件。

2,broadcast 是向任意指定的后代组件通信。

实现思路,先在指定的后代组件中使用 this.$on() 监听事件 event1。父组件需要触发后代组件监听的事件 event1 时,会递归遍历子组件找到指定的后代组件,通过 $emit() 触发监听的事件。

实现

element-ui 的实现

element-ui 是基于自己的考虑来使用的,比如表单组件的传参验证等,基于组件树但层级不深并且可控。

// 因为会被递归调用,所以写到外面
function broadcast(componentName, eventName, params) {
    
    
  this.$children.forEach((child) => {
    
    
    var name = child.$options.componentName; // componentName 是约定的组件标识

    if (name === componentName) {
    
    
      child.$emit.apply(child, [eventName].concat(params));
    } else {
    
    
      // 递归调用
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
export default {
    
    
  methods: {
    
    
    dispatch(componentName, eventName, params) {
    
    
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName; // componentName 是约定的组件标识

      while (parent && (!name || name !== componentName)) {
    
    
        parent = parent.$parent;

        if (parent) {
    
    
          name = parent.$options.componentName;
        }
      }
      if (parent) {
    
    
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
    
    
      broadcast.call(this, componentName, eventName, params);
    },
  },
};

dispatch 使用举例

A<–B<–C(A是祖先组件)

// 触发祖先组件 A 的 eventParent 事件,并传参 123
this.dispatch('A', 'eventParent', 123)

举例:

<!-- A组件 -->
<template>
  <BComponent />
</template>

<script>
import BComponent from "./components/B.vue";
export default {
      
      
  componentName: "A",
  components: {
      
      
    BComponent,
  },
  methods: {
      
      
    methodParent(item) {
      
      
      console.log(item);
    },
  },
  created() {
      
      
    this.$on("eventParent", this.methodParent);
  },
};
</script>
<!-- B组件 -->
<template>
  <CComponent />
</template>

<script>
import CComponent from "./C.vue";
export default {
      
      
  components: {
      
      
    CComponent,
  },
};
</script>
<!-- C组件 -->
<template>
  <button @click="handleClick">触发祖先组件A的方法</button>
</template>

<script>
import Emitter from "@/mixins/emitter.js";
export default {
      
      
  mixins: [Emitter],
  methods: {
      
      
    handleClick() {
      
      
      this.dispatch("A", "eventParent", 123);
    },
  },
};
</script>

broadcast 使用举例

A<–B<–C(A是祖先组件)

// 触发后代组件 C 的 eventChild 事件,并传参 123
this.broadcast('C', 'eventChild', 123)

举例,

<!-- A组件 -->
<template>
  <div>
    <BComponent />
    <button @click="handleClick">触发后台组件C的方法</button>
  </div>
</template>

<script>
import BComponent from './components/B.vue'
import Emitter from '@/mixins/emitter.js'
export default {
      
      
  components: {
      
      
    BComponent
  },
  mixins: [Emitter],
  methods: {
      
      
    handleClick() {
      
      
      this.broadcast('C', 'eventChild', 123) // 会触发 eventChild 事件绑定的2个处理函数。
    }
  }
}
</script>
<!-- B组件 -->
<template>
  <CComponent />
</template>

<script>
import CComponent from './C.vue'
export default {
      
      
  components: {
      
      
    CComponent
  }
}
</script>
<!-- C组件 -->
<template></template>

<script>
export default {
      
      
  componentName: 'C',
  methods: {
      
      
    methodC1(item) {
      
      
      console.log(item)
    },
    methodC2(item) {
      
      
      console.log(item)
    }
  },
  created() {
      
      
    this.$on('eventChild', this.methodC1)
    this.$on('eventChild', this.methodC2)
  }
}
</script>

以上。

猜你喜欢

转载自blog.csdn.net/qq_40147756/article/details/133141796