vue篇之事件总线(EventBus)

许多现代JavaScript框架和库的核心概念是可以将数据和UI封装在模块化、可重用的组件中。这对于开发人员能够在开发整个应用程序时避免使用编写大量重复的代码。虽然这样作很是有用,但也涉及到组件之间的数据通信。在Vue中一样有这样的概念存在。经过前面一段时间的学习,Vue组件数据通信经常会有父子组件,兄弟组件之间的数据通信。也就是说在Vue中组件通信有必定的原则。前端

父子组件通信原则

为了提升组件的独立性与重用性,父组件会经过 props 向下传数据给子组件,当子组件有事情要告诉父组件时会经过 $emit 事件告诉父组件。如此确保每一个组件都是独立在相对隔离的环境中运行,能够大幅提升组件的维护性。vue

在《Vue组件通信》一文中有详细介绍过这部分。但这套通信原则对于兄弟组件之间的数据通信就有必定的诟病。固然,在Vue中有其余的方式来处理兄弟组件之间的数据通信,好比Vuex这样的库。但在不少状况之下,我们的应用程序不须要相似Vuex这样的库来处理组件之间的数据通信,而能够考虑Vue中的 事件总线 ,即 **EventBus **。设计模式

接下来的内容,就是来一块儿学习Vue中的 EventBus 相关的知识点。bash

EventBus的简介

EventBus 又称为事件总线。在Vue中可使用 EventBus 来做为沟通桥梁的概念,就像是全部组件共用相同的事件中心,能够向该中心注册发送事件或接收事件,因此组件均可以上下平行地通知其余组件,但也就是太方便因此若使用不慎,就会形成难以维护的灾难,所以才须要更完善的Vuex做为状态管理中心,将通知的概念上升到共享状态层次。app

如何使用EventBus

在Vue的项目中怎么使用 EventBus 来实现组件之间的数据通信呢?具体能够经过下面几个步骤来完成。框架

初始化

首先你须要作的是建立事件总线并将其导出,以便其它模块可使用或者监听它。咱们能够经过两种方式来处理。先来看第一种,新建立一个 .js 文件,好比 event-bus.js :模块化

// event-bus.js


import Vue from 'vue'
export const EventBus = new Vue()
复制代码

你须要作的只是引入 Vue 并导出它的一个实例(在这种状况下,我称它为 EventBus )。实质上它是一个不具有 DOM 的组件,它具备的仅仅只是它实例方法而已,所以它很是的轻便。学习

另一种方式,能够直接在项目中的 main.js 初始化 EventBus :ui

// main.js
Vue.prototype.$EventBus = new Vue()
复制代码

注意,这种方式初始化的 EventBus 是一个 全局的事件总线 。稍后咱们会花点时间专门聊一聊全局的事件总线。this

如今咱们已经建立了 EventBus ,接下来你须要作到的就是在你的组件中加载它,而且调用同一个方法,就如你在父子组件中互相传递消息同样。

发送事件

假设你有两个子组件: DecreaseCount 和 IncrementCount ,分别在按钮中绑定了 decrease()和 increment() 方法。这两个方法作的事情很简单,就是数值递减(增) 1 ,以及角度值递减(增) 180 。在这两个方法中,经过 EventBus.$emit(channel: string, callback(payload1,…)) 监听 decreased (和 incremented )频道。

<!-- DecreaseCount.vue -->
<template>
    <button @click="decrease()">-</button>
</template>

<script> import { EventBus } from "../event-bus.js";
    export default {
        name: "DecreaseCount",
        data() {
            return {
                num: 1,
                deg:180
            };
        },
        methods: {
            decrease() {
                EventBus.$emit("decreased", {
                    num:this.num,
                    deg:this.deg
                });
            }
        }
    }; 
</script>

<!-- IncrementCount.vue -->
<template>
    <button @click="increment()">+</button>
</template>

<script> import { EventBus } from "../event-bus.js";
    export default {
        name: "IncrementCount",
        data() {
            return {
                num: 1,
                deg:180
            };
        },
        methods: {
            increment() {
                EventBus.$emit("incremented", {
                    num:this.num,
                    deg:this.deg
                });
            }
        }
    };
 </script>
复制代码

上面的示例,在 DecreaseCount 和 IncrementCount 分别发送出了 decreased 和 incremented频道。接下来,咱们须要在另外一个组件中接收这两个事件,保持数据在各组件之间的通信。

接收事件

如今咱们能够在组件 App.vue 中使用 EventBus.$on(channel: string, callback(payload1,…))监听 DecreaseCount 和 IncrementCount 分别发送出了 decreased 和 incremented 频道。

<!-- App.vue -->
<template>
    <div id="app">
        <div class="container" :style="{transform: 'rotateY(' + degValue + 'deg)'}">
            <div class="front">
                <div class="increment">
                    <IncrementCount />
                </div>
                <div class="show-front"> {{fontCount}} </div>
                <div class="decrement">
                    <DecreaseCount />
                </div>
            </div>

            <div class="back">
                <div class="increment">
                    <IncrementCount />
                </div>
                <div class="show-back"> {{backCount}} </div>
                <div class="decrement">
                    <DecreaseCount />
                </div>
            </div> 
        </div>
    </div>
</template>

<script>
    import IncrementCount from "./components/IncrementCount";
    import DecreaseCount from "./components/DecreaseCount";
    import { EventBus } from "./event-bus.js";
    export default {
        name: "App",
        components: {
            IncrementCount,
            DecreaseCount
        },
        data() {
            return {
                degValue:0,
                fontCount:0,
                backCount:0
            };
        },
        mounted() {
            EventBus.$on("incremented", ({num,deg}) => {
                this.fontCount += num
                this.$nextTick(()=>{
                    this.backCount += num
                    this.degValue += deg;
                })
            });
            EventBus.$on("decreased", ({num,deg}) => {
                this.fontCount -= num
                this.$nextTick(()=>{
                    this.backCount -= num
                    this.degValue -= deg;
                })
            });
        }
    }; 
</script>
复制代码

最终获得的效果以下:

最后用一张图来描述示例中用到的 EventBus 之间的关系:

若是你只想监听一次事件的发生,可使用 EventBus.$once(channel: string, callback(payload1,…)) 。

移除事件监听者

若是想移除事件的监听,能够像下面这样操做:

import { eventBus } from './event-bus.js'
EventBus.$off('decreased', {})
复制代码

你也可使用 EventBus.$off(‘decreased’) 来移除应用内全部对此事件的监听。或者直接调用EventBus.$off() 来移除全部事件频道, 注意不须要添加任何参数 。

上面就是 EventBus 的使用方式,是否是很简单。上面的示例中咱们也看到了,每次使用 EventBus 时都须要在各组件中引入 event-bus.js 。事实上,咱们还能够经过别的方式,让事情变得简单一些。那就是建立一个全局的 EventBus 。接下来的示例向你们演示如何在Vue项目中建立一个全局的 EventBus 。

全局EventBus

全局EventBus,虽然在某些示例中不提倡使用,但它是一种很是漂亮且简单的方法,能够跨组件之间共享数据。

它的工做原理是发布/订阅方法,一般称为 Pub/Sub 。

这整个方法能够看做是一种设计模式,由于若是你查看它周围的东西,你会发现它更像是一种体系结构解决方案。咱们将使用普通的JavaScript,并建立两个组件,并演示EventBus的工做方式。

让咱们看看下图,并试着了解在这种状况下究竟发生了什么。

咱们从上图中能够得出如下几点:

  • 有一个全局EventBus
  • 全部事件都订阅它
  • 全部组件也发布到它,订阅组件得到更新
  • 总结一下。全部组件都可以将事件发布到总线,而后总线由另外一个组件订阅,而后订阅它的组件将获得更新

在代码中,咱们将保持它很是小巧和简洁。咱们将它分为两部分,将展现两个组件以及生成事件总线的代码。

建立全局EventBus

全局事件总线只不过是一个简单的 vue 组件。代码以下:

var EventBus = new Vue();

Object.defineProperties(Vue.prototype, {
    $bus: {
        get: function () {
            return EventBus
        }
    }
})
复制代码

如今,这个特定的总线使用两个方法 $on 和 $emit 。一个用于建立发出的事件,它就是$emit ;另外一个用于订阅 $on :

var EventBus = new Vue();

this.$bus.$emit('nameOfEvent',{ ... pass some event data ...});

this.$bus.$on('nameOfEvent',($event) => {
    // ...
})
复制代码

如今,咱们建立两个简单的组件,以便最终得出结论。

接下来的这个示例中,咱们建立了一个 ShowMessage 的组件用来显示信息,另外建立一个 UpdateMessage 的组件,用来更新信息。

在 UpdateMessage 组件中触发须要的事件。在这个示例中,将触发一个 updateMessage 事件,这个事件发送了 updateMessage 的频道:

<!-- UpdateMessage.vue -->
<template>
    <div class="form">
        <div class="form-control">
            <input v-model="message" >
            <button @click="updateMessage()">更新消息</button>
        </div>
    </div>
</template>
<script>
export default {
        name: "UpdateMessage",
        data() {
            return {
                message: "这是一条消息"
            };
        },
        methods: {
            updateMessage() {
                this.$bus.$emit("updateMessage", this.message);
            }
        },
        beforeDestroy () {
            $this.$bus.$off('updateMessage')
        }
    };
 </script>
复制代码

同时在 ShowMessage 组件中监听该事件:

<!-- ShowMessage.vue -->
<template>
    <div class="message">
        <h1>{{ message }}</h1>
    </div>
</template>

<script> 
export default {
        name: "ShowMessage",
        data() {
            return {
                message: "我是一条消息"
            };
        },
        created() {
            var self = this
            this.$bus.$on('updateMessage', function(value) {
                self.updateMessage(value);
            })
        },
        methods: {
            updateMessage(value) {
                this.message = value
            }
        }
    }; 
</script><
复制代码

最终的效果以下:

从上面的代码中,咱们能够看到 ShowMessage 组件侦听一个名为 updateMessage 的特定事件,这个事件在组件实例化时被触发,或者你能够在建立组件时触发。另外一方面,咱们有另外一个组件UpdateMessage ,它有一个按钮,当有人点击它时会发出一个事件。这致使订阅组件侦听发出的事件。这产生了 Pub/Sub 模型,该模型在兄弟姐妹之间持续存在而且很是容易实现。

总结

本文主要经过两个实例学习了Vue中有关于 EventBus 相关的知识点。主要涉及了 EventBus 如何实例化,又是怎么经过 $emit 发送频道信号,又是如何经过 $on 来接收频道信号。最后简单介绍了怎么建立全局的 EventBus 。从实例中咱们能够了解到, EventBus 能够较好的实现兄弟组件之间的数据通信。 对前端技术感兴趣的同窗,欢迎加入Q群:866109386,无论你是小白仍是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时天天更新视频文件资料。 最后,祝你们早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

相关文章
相关标签/搜索