• 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);
        },
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    dispatch 使用举例

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

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

    举例:

    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    
    <template>
      <CComponent />
    template>
    
    <script>
    import CComponent from "./C.vue";
    export default {
      components: {
        CComponent,
      },
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    broadcast 使用举例

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

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

    举例,

    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    
    <template>
      <CComponent />
    template>
    
    <script>
    import CComponent from './C.vue'
    export default {
      components: {
        CComponent
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以上。

  • 相关阅读:
    ISL1208时钟芯片 Linux下 i2c 设置报警时钟。
    金仓数据库 KingbaseES 插件参考手册 pldbgapizw33
    掌握未来技术趋势,Python编程引领人工智能时代
    OOP 向量加减(友元+拷贝构造)
    python打包相关
    第03章_用户与权限管理
    一个 MySQL 隐式转换的坑,差点把服务器整崩溃了
    【LVGL布局】柔性布局
    Redis的高可用——主从复制、哨兵模式、Redis群集部署
    一文读懂什么是 OCR 识别
  • 原文地址:https://blog.csdn.net/qq_40147756/article/details/133141796