Глобальная шина событий Vue.js
Я пытаюсь создать глобальную шину событий так, чтобы два компонента sibling могли взаимодействовать друг с другом. Я искал вокруг; однако я не могу найти примеров того, как его реализовать. Это то, что у меня есть до сих пор:
var bus = new Vue();
Vue.component('Increment', {
template: "#inc",
data: function() {
return ({count: 0})
},
methods: {
increment: function(){
var increment = this.count++
bus.$emit('inc', increment)
}
}
})
Vue.component('Display', {
template: "#display",
data: function(){
return({count: 0})
},
created: function(){
bus.$on('inc', function(num){
alert(num)
this.count = num;
});
}
})
vm = new Vue({
el: "#example",
})
Я создал свои шаблоны так: http://codepen.io/p-adams/pen/PzpZBg
Я хотел бы, чтобы компонент Increment
передавал счету компоненту Display
. Я не уверен, что я делаю неправильно в bus.$on()
.
Ответы
Ответ 1
Проблема в том, что в вашей функции bus.$on
On this
относится к шине. Вам просто нужно привязать текущий экземпляр Vue к этой функции, используя .bind()
:
bus.$on('inc', function(num){
alert(num)
this.count = num;
}.bind(this));
Вам также следует проверить https://github.com/vuejs/vuex, если вы хотите управлять глобальными состояниями приложений.
РЕДАКТИРОВАТЬ: Поскольку эта страница, кажется, получает много кликов, я хочу отредактировать и добавить другой метод, согласно ChristopheMarois в комментариях:
РЕДАКТИРОВАТЬ: В попытке сделать этот ответ немного яснее, и поэтому будущие читатели не должны читать комментарии здесь, что происходит:
Использование жирной стрелки, как показано ниже, связывает лексическую область "this" с компонентом, а не с шиной событий.
bus.$on('inc', (num) => {
alert(num);
this.count = num;
});
Или удаление оповещения:
bus.$on('inc', (num) => this.count = num);
Ответ 2
Когда вы пишете JavaScript ES5, вы должны знать о том, что то, что вы называете с помощью ключевого слова this
, может измениться, в соответствии с областью действия оно вызывается из.
Полезной метафорой, чтобы окунуться в концепцию this
, является мысль о фигурных скобках в ES5 как о заборе, которые содержат/связывают ее собственный this
.
Когда вы используете this
в функции обратного вызова вашей шины событий, this
не ссылается на ваш компонент Vue, а на объект шины, который не имеет данных счета, поэтому данные, которые вы ожидаете обновить, не.
Если у вас есть/хотите написать синтаксис ES5, общее обходное решение (помимо привязки this
, как предложено принятым ответом), нужно назначить ключевое слово this
такой переменной:
created: function(){
var self = this;
bus.$on('inc', function(num){
alert(num)
self.count = num;
});
}
Если вы можете написать ES6, сделайте это, когда это возможно. Вы всегда можете скомпилировать/перевести на ES5 с помощью Babel. Принятый ответ показывает, как с помощью функций стрелок.
Функции стрелок работают в этом случае, потому что они не связывают свои собственные this
.
Чтобы придерживаться метафоры ограждения: представьте себе стрелку ES6, выталкивающую отверстие в вашей функции, поэтому внешний this
может пройти, и вы можете вызвать this
по назначению.
Чтобы узнать больше о функциях стрелок ES6, посетите:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Ответ 3
Это ответ длинным, вот мое решение, использующее vue.js-2
main.js
import Vue from 'vue'
import App from './App'
export const eventBus = new Vue({
methods:{
counter(num) {
this.$emit('addNum', num);
}
}
});
new Vue({
el: '#app',
template: '<App/>',
components: { App }
});
comp1.vue
//Calling my named export
import { eventBus } from '../../main'
<template>
<div>
<h1>{{ count }}</h1>
<button @click="counterFn">Counter</button>
</div>
</template>
<script>
import { eventBus } from '../../main'
export default {
name: 'comp-one',
data() {
return {
count: 0
}
},
methods: {
counterFn() {
eventBus.counter(this.count);
}
},
created() {
eventBus.$on('addNum', () => {
this.count++;
})
}
}
</script>
Ответ 4
Как насчет этого? Предположим, что Vue.js 2.
Создайте повторно используемый компонент Event-Bus и привяжите его к Vue
с помощью шаблона плагина:
// ./components/EventBus.vue
import Vue from 'vue'
export const EventBus = new Vue()
// ./plugins/EventBus.js
export default {
install(Vue) {
const { EventBus } = require('../components/EventBus')
Vue.prototype.$bus = EventBus
}
}
// ./main.js
import EventBus from './plugins/EventBus'
Vue.use(EventBus)
Затем вы можете делать в любом месте своего кода:
this.$bus.$emit('some-event', payload)
В качестве побочного примечания попробуйте использовать шаблон Event-Bus в качестве последнего средства.