Шина событий (EventBus) в vue

Vue.js EventBus

Основной концепцией многих современных фреймворков и библиотек JavaScript является возможность инкапсулировать данные и пользовательский интерфейс в модульные повторно используемые компоненты. Это позволяет разработчикам избежать написания большого количества повторяющегося кода при разработке всего приложения. Хотя это очень полезно, это также включает обмен данными между компонентами. Эта концепция также существует в Vue. В течение предыдущего периода обучения передача данных компонента Vue часто имела компоненты «родитель-потомок» и передачу данных между одноуровневыми компонентами. Другими словами, в Vue существуют определенные принципы взаимодействия компонентов.

Принцип связи родительско-дочерний компонент

Чтобы улучшить независимость и возможность повторного использования компонентов, родительский компонент будет проходитьpropsПередайте данные дочернему компоненту, когда дочернему компоненту есть что сказать родительскому компоненту, он передаст$emitСобытия сообщают родительскому компоненту. Это гарантирует, что каждый компонент работает независимо в относительно изолированной среде, что может значительно повысить удобство сопровождения компонентов.

Эта часть подробно описана в статье «Общение компонентов Vue». Однако этот набор принципов связи имеет определенные критические замечания в отношении обмена данными между одноуровневыми компонентами. Конечно, есть и другие способы управления обменом данными между родственными компонентами в Vue, например библиотеки вроде Vuex. Но во многих случаях наше приложение не нуждается в такой библиотеке, как Vuex, для обработки обмена данными между компонентами, и может использовать Vue в  автобус событий ,который **EventBus**.

Следующий контент — совместное обучение во Vue.EventBusсоответствующие очки знаний.

Введение в EventBus

EventBusТакже известен как шина событий. Доступно в VueEventBusЧто касается концепции коммуникационного моста, то все компоненты используют один и тот же центр событий, вы можете зарегистрироваться в центре для отправки или получения событий, поэтому компоненты могут уведомлять другие компоненты параллельно, но это слишком удобно, поэтому, если вы используете это небрежно, это вызовет катастрофу, которую трудно поддерживать, поэтому необходим более полный Vuex в качестве центра управления состоянием, а концепция уведомления поднята до уровня общего состояния.

Как использовать EventBus

Как использовать его в проекте VueEventBusКак насчет передачи данных между компонентами? В частности, это можно сделать с помощью следующих шагов.

инициализация

Первое, что вам нужно сделать, это создать шину событий и экспортировать ее, чтобы другие модули могли ее использовать или прослушивать. Мы можем справиться с этим двумя способами. Посмотрим на первый, создадим новый.jsфайл, напримерevent-bus.js:

// event-bus.js


import Vue from 'vue'
export const EventBus = new Vue()

Все, что вам нужно сделать, это импортировать Vue и экспортировать его экземпляр (в этом случае я назову егоEventBus). По сути, это компонент, у которого нет DOM, все, что у него есть, — это методы экземпляра, поэтому он очень легкий.

Другой способ, можно прямо в проектеmain.jsинициализацияEventBus:

// main.js
Vue.prototype.$EventBus = new Vue()

Обратите внимание, что инициализированный таким образомEventBus Является глобальная шина событий. Позже мы потратим некоторое время на разговор о глобальной шине событий.

Теперь мы создали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, хотя в некоторых примерах и не рекомендуется, является очень изящным и простым способом обмена данными между компонентами.

Он работает на основе подхода публикации/подписки, обычно называемогоPub/Sub.

Весь этот подход можно рассматривать как шаблон проектирования, потому что, если вы посмотрите вокруг, это скорее архитектурное решение. Мы будем использовать простой JavaScript, создадим два компонента и продемонстрируем, как работает 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Это может лучше реализовать передачу данных между одноуровневыми компонентами.