不用vuex的情况下,隔代组件间的通信

优点:适合开发层级不会很复杂的独立组件,无需借助vuex

缺点:依赖组件树的结构,比如需要知道A和B谁是父,谁是子,然后父中broadcast,子中dispatch。


先列一个简单的case:

<!--child.vue-->
export default {
  methods: {
    handleEmitEvent () {
      this.$emit('test', 'Hello Vue.js')
    }
  }
}
复制代码
<!--parent.vue-->
<template>
  <child-component @test="handleEvent">
</template>
<script>
  export default {
    methods: {
      handleEvent (text) {
      	console.log(text)  // Hello Vue.js
      }
    }
  }
</script>
复制代码

子组件触发($emit),父组件监听($on)。

So, 既然是子组件自己触发的,那它自己也可以监听到, 即组件自己监听自己的emit。

<template>
  <div>
    <button @click="handleEmitEvent">触发自定义事件</button>
  </div>
</template>
<script>
  export default {
    methods: {
      handleEmitEvent () {
        this.$emit('test', 'Hello Vue.js')
      }
    },
    created () {
      this.$on('test', (text) => {
         console.log(text) // Hello Vue.js
      });
    }
  }
</script>
复制代码

乍一看多次一举, handleEmitEvent可以直接写逻辑,没必要emit,on这样绕了一圈

如果handleEmitEvent不是通过该组件自身调用的呢?

设想这样的场景,A是父组件,B是子组件,中间可能跨多级。 A向B通信:

<!--A.vue-->
<template>
	<input @focus="handleFocus">触发事件 />
</template>
<script>
  import Emitter from '../mixins/emitter.js'; // 先忽略混入的内容
  export default {
    name: 'componentA',
    mixins: [ Emitter ],
    methods: {
      handleFocus () {
        this.broadcast('componentB', 'sendMessage', '我被点了'); // 后面会放实现逻辑
      }
    }
  }
</script>
复制代码
<!--B.vue-->
<script>
export default {
  name: 'componentB',
  created () {
    this.$on('sendMessage', this.showMessage)
  },
  methods: {
    showMessage (text) {
      console.log(text); // 我被点了
    }
  }
}
</script>
复制代码

事件触发点是A组件中的input被focus,但是为什么B组件中可以监听到呢?

看完下面Emitter的实现就明白了。

function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    const name = child.$options.name;

    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) {
      let parent = this.$parent || this.$root;
      let name = parent.$options.name;

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

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

通过mixins可以将dispatch和broadcast方法merge到A组件中,

broadcast就是向下递归遍历通过name寻找指定的组件(componentB), dispatch同理。

实际上最终还是在找到的B中调用$emit触发自定义事件,所以B也就可以监听到该事件的触发,

但是事件的源头却是从A触发,也就实现了A和B的通信。


参考 Vue.js组件精讲 juejin.im/book/5bc844…

注:emitter.js 参考 github.com/iview/iview…

转载于:https://juejin.im/post/5caf64e25188251acc538f9c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值