zoukankan      html  css  js  c++  java
  • Vue2.0父子组件间事件派发机制

    从vue1.x过来的都知道,在vue2.0中,父子组件间事件通信的$dispatch$broadcase被移除了。官方考虑是基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的过程中会变得越来越脆落。特别是在组件层级比较深的情况下。通过广播和事件分发的机制,就显得比较混乱了。

    官方在废除的同时,也为我们提供了替换方案,包括实例化一个空的vue实例,使用$emit反应子组件上的状态变化

    1.使用$emit触发事件

    helloWorld.vue作为父组件,dialogConfigVisible变量控制子组件弹框显示或隐藏。
    configBox.vue作为子组件,假设为封装的公告弹窗。

    在父组件中 helloWorld.vue 中

    < template/>

    
       &lt;config-box
         :visible="dialogConfigVisible"                
          @listenToConfig="changeConfigVisible"
      &gt; &lt;/config-box&gt;
    
    

    script

    
      data(){
        return {
          dialogConfigVisible:true
        }
      }
       methods: {
         changeConfigVisible(flag) {
             this.dialogConfigVisible = flag;
         }
       }
    

    然后,在子组件 configBox.vue 中,主要在任意事件回调中,使用 $emit来触发自定义的 listenToConfig事件,后面还可以加上参数传给父组件。比如,在子组件弹窗上点击×关闭时,通知父组件 helloWorld.vue我要关闭了,主要方便父组件改变相应状态变量,并传入false到自定义的事件中。

    script

    
    methods:{
      dialogClose() {
        this.show = false;
        this.$emit("listenToConfig", false)
      }
    }
    
    

    在子組件中,主动触发listenToConfig事件,并传入参数 false, 告诉父组件 helloWorld.vue对话框要关闭了。这里就可以避免父组件中的状态未变化,再次刷新页面的时候对话框会自动出现。

    2.实例化一个空的vue实例bus

    这里实例化一个bus 空vue实例,主要为了统一管理子组件和父组件相互通信,通过bus 作为媒介,
    首先新建一个bus.js 文件,在里面新建一个对象,父组件为table.vue, 子组件为tableColumn.vue

    
      // bus.js
     import Vue from "vue";
     export var bus = new Vue({
         data:{
           scrollY:false
         },
         methods:{
            updateScrollY(flag){
              this.scrollY = flag;
            }
         }
       })
    

    然后分别引入:

    
     // table.vue
     &lt;script&gt;
      import {bus}  from "./bus"
       export default {
          created(){
            bus.$on('getData',(argsData)=&gt;{
              // 这里获取子组件传来的参数
              console.log(argsData);
              })
    
          }
       }
    
      &lt;/script&gt;
    
      // tableColumn.vue
      &lt;script&gt;
        import {bus} from "./bus"
        export default{
          methods(){
            handleClick(){
              bus.$emit('getData',{data:"from tableColumn!"})
            }
          }
        }
      &lt;/script&gt;
    
    

    上面的父子组件中,父组件中利用bus注册监听事件getData,子组件中一旦有状态变化,就触发bus上对应的事件。

    这种利用空实例的方式,相当于创建了一个事件中心,所以这种通信同样适用于非父子组件间的通信,

    3.多级父子组件通信

    有时,可能想要实现通信的两个组件不是直接的父子组件,而是祖父和孙子,或者是跨越了更多层级的父子组件

    不可能由子组件一级一级的向上传递参数,来达到通信的目的,虽然现在我们理解的通信都是这样经过中转的。可以通过while等循环,不断向上遍历,直到找到目标父组件,就在对应的组件上触发事件。

    下面就只element-ui实现的一个父子组件通信的mixins,对于组件同步有很大的作用。在element-ui 的优点概述中也特意提到这个组件通信

    
    function broadcast(componentName, eventName, params) {
    
      // 向下遍历每个子节点,触发相应的向下广播的 事件
      this.$children.forEach(child =&gt; {
        var name = child.$options.componentName;
    
        if (name === componentName) {
          child.$emit.apply(child, [eventName].concat(params));
        } else {
          broadcast.apply(child, [componentName, eventName].concat([params]));
        }
      });
    }
    export default {
      methods: {
         // 向上遍历父节点,来获取指定父节点,通过$emit 在相应的 组件中触发 eventName  事件
        dispatch(componentName, eventName, params) {
          var parent = this.$parent || this.$root;
          var name = parent.$options.componentName;
          // 上面的componentName 需要在每个vue 实例中额外配置自定义属性 componentName,
          //可以简单替换成var name = parent.$options._componentTag;
    
          while (parent &amp;&amp; (!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);
        }
      }
    };
    
    

    首先定义两个嵌套的组件 f1.vue 和 c1.vue,实例是:

    
     &lt;f1&gt;
       &lt;c1&gt;&lt;/c1&gt;
     &lt;/f1&gt;
    

    然后,分别定义两个父子组件:

    
    c2.vue
    
     &lt;template&gt;
         &lt;section&gt;
         &lt;button type="button" name="button" @click="dispatchTest"&gt;点击一下,就可以&lt;/button&gt;
       &lt;/section&gt;
     &lt;/template&gt;
    &lt;script type="text/javascript"&gt;
    import Emitter from "../mixins/emitter";
    export default {
    name: "c2",
    mixins: [Emitter],
    componentName:'c2',
    methods: {
      dispatchTest() {
        this.dispatch('f1', 'listenerToC1', false);
      }
    }
    }
    &lt;/script&gt;
    
    
     f1.vue
    
    &lt;template type="html"&gt;
      &lt;div class="outBox-class"&gt;
        &lt;slot&gt;
        &lt;/slot&gt;
      &lt;/div&gt;
    &lt;/template&gt;
    
    &lt;script type="text/javascript"&gt;
    import Emitter from "../mixins/emitter";
    export default {
    name: "f1",
    mixins: [Emitter],
    componentName: 'f1',
    mounted() {
      this.$on("listenerToC1", (value) =&gt; {
         alert(value);
      })
    }
    }
    &lt;/script&gt;
    

    这样,就可以在子组件中点击按钮,触发 listenerToC1事件,在父组件中监听到这个事件,
    其实更$emit触发事件类似。不同之处在于,这里可以多级嵌套,不一定是直接的父子组件都可以触发到。

    4 .sync 修饰符

    在Vue1.x中,利用prop进行"双向绑定",实现父子组件通信,都会用到.sync修饰符,可以将子组件中对应的prop值变化同步到父组件中。但是,这样就破坏了单向数据流,在2.0版本中被移除了,在2.3.0版本中又以一种语法糖的形式加了进来。
    可以看下文档上给出的实例

    
       &lt;comp :foo.sync=“bar”&gt;&lt;/comp&gt;
    

    被扩展为

    
      &lt;comp :foo="bar" @update:foo= "val =&gt;bar=val"&gt;&lt;/comp&gt;
    

    其实跟本文中第一种方法基本一致,更加简化了。

    同样helloWorld.vue作为父组件, configBox.vue作为子组件,

    
         &lt;config-box
         :visible.sync="dialogConfigVisible"                
      &gt; &lt;/config-box&gt;
    

    然后在子组件中,显式的触发更新事件:

    
    methods:{
      dialogClose() {
        this.show = false;
        this.$emit("update:visible", false)
      }
    }
    
    

    这样visible 的变化就能同步到父组件中了。

    原文地址:https://segmentfault.com/a/1190000012729649

  • 相关阅读:
    107. Binary Tree Level Order Traversal II
    108. Convert Sorted Array to Binary Search Tree
    111. Minimum Depth of Binary Tree
    49. Group Anagrams
    使用MALTAB标定实践记录
    442. Find All Duplicates in an Array
    522. Longest Uncommon Subsequence II
    354. Russian Doll Envelopes
    opencv 小任务3 灰度直方图
    opencv 小任务2 灰度
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9960139.html
Copyright © 2011-2022 走看看