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

  • 相关阅读:
    Mac实用快捷键大全
    Java 12 新特性概述
    java sdk官网直接下载地址
    使用SqlBulkCopy类实现导入excel表格
    框架页面高度自动刷新Javascript脚本
    从MyEclipse到IntelliJ IDEA ——让你脱键盘,全键盘操作
    带你走进EJB--将EJB发布为Webservice(1)
    带你走进EJB--将EJB发布为Webservice(2)
    poj 3042 Grazing on the Run
    算法导论:比较排序算法笔记
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9960139.html
Copyright © 2011-2022 走看看