Динамическая компонентная шина событий не работает в Vue? - PullRequest
0 голосов
/ 15 мая 2018

Я просто использовал шину событий в vuejs для динамического компонента, но когда я генерирую событие из одного компонента, я не могу прослушать это событие в другом компоненте.Ниже приведена демонстрация, которую я создал с помощью codesandbox. Я хочу вывести «test in tes2» из test2component, но он ничего не выводит.Но когда я раскомментирую прослушиватель $ bus в HomeCompnent, все console.log все выполняются.

main.js

Vue.propotype.$bus = new Vue();

HomeComponent

<template>
  <div>
    <component :is="currentComponent" @changeComponent="changeComponent"></component>
  </div>
</template>

<script>
import Test1Component from "./Test1Component";
import Test2Component from "./Test2Component";

export default {
  created() {
    // this.$bus.$on("test", () => console.log("event bus test"));
  },
  components: {
    Test1Component,
    Test2Component
  },
  data() {
    return {
      currentComponent: "Test1Component"
    };
  },
  methods: {
    changeComponent() {
      this.currentComponent = "Test2Component";
    }
  }
};
</script>

<style>

</style>

Test1Component

<template>
  <div>
    <h1>test1</h1>
    <button @click="changeComponent">click me</button>
  </div>
</template>

<script>
export default {
  methods: {
    changeComponent() {
      this.$emit("changeComponent");
      this.$bus.$emit("test");
    }
  }
};
</script>

<style>

</style>

Test2Component

<template>
  <h1>test2</h1>
</template>

<script>
export default {
  created() {
    this.$bus.$on("test", () => console.log("test in test2"));
  }
};
</script>

<style>

</style>

Edit Vue Template

Ответы [ 3 ]

0 голосов
/ 15 мая 2018

Эта проблема является хорошей демонстрацией недостатков шаблона шины событий:

Вы, разработчик, должны тщательно убедиться, что отправитель и получатель всех событий действительно существуют в одно и то же время.

В вашем сценарии это не так:

  • Когда Test1Component отправляет событие, Test2Component еще не существует.
  • После того, как Test2Component был создан HomeComponent простомгновение спустя событие уже «ушло».

Мой обычный отказ от ответственности в качестве члена основной команды Vue: не используйте шаблон шины событий.

0 голосов
/ 15 мая 2018

Event Bus - это нормально, но проблема в реализации.

Вы очень правы, если вы un-comment code В домашнем компоненте, который я тестировал на вашем фрагменте, он испускает только один раз event bus test [консоль.log]

С событиями вам нужно позаботиться об этом

  1. Необходимо определить слушателя.[убедитесь, что вы определили их перед отправкой события]
  2. Теперь вы просто отправляете событие.[для работы нам нужно, чтобы слушатель слушал первым]

В вашем случае вы написали listener function $on в created событии Test2Component

Теперь просто подумайте, Выу вас нет слушателей в начале, как в home compo, вы только что прокомментировали этот код слушателя. [его начальный шаг]

Теперь, когда вы нажимаете кнопку click me, вы changing компонент для нового компонента [Test2Component], он монтируется и его событие created сработает then this listener will start listening to event

, но вы пропустили это

this.$emit("changeComponent"); // this is first [ fires/emit ]
this.$bus.$emit("test"); // THEN THIS EMIT

Итак, когда это простозапуск changing компонент из compo1 to compo2 тест fired/emitted directly without wait, its not синхронный it is A синхронный It will not wait to finish all stuff of changeComponent . It will be emitted immediately [ test`]

Угадайте, что Теперь, когда test испускает, в это время Dom operation to add component, ITS NOT DONE YET, и test испускается

Итак, No listeners are there, поэтому нет console.log

Но если вы видите, что вы UNCOMMENT listener в слушателе домашней функции хорошо определены до emit of test event, так что он выводится в консоли.

Я надеюсь, вы понимаете, если нет, дайте мне знатьЯ будуЯ объясню это более подробно

Еще одно, что вы добавили $ bus в prototype, чтобы все компоненты имели свою собственную шину.вместо этого вы можете использовать GLOBAL event Bus

, как в примере, который вы видите.

в es6 вы можете сделать

//bus.js
const bus = new Vue({});
export default bus;

, чтобы импортировать его в другие компоненты

import bus from './bus.js';

// ... do bus.$on ..
// ... do bus.$emit ..    

var $bus = new Vue({});

Vue.component('Test1', {
	template: `
		<div class="blog-post">
			<h3>test1</h3>
      <button @click="changeComponent">click me</button>
		</div>
	`,
  methods: {
    changeComponent() {
      $bus.$emit("chng");
      $bus.$emit("test");
    }
  }
});

Vue.component('Test2', {
	template: `
		<div class="blog-post">
			<h3>test2</h3>
		</div>
	`,
  created() {
    $bus.$on("test", () => console.log("test in test2 will not fire as we are little late to listen it"));
  }
});


new Vue({
	el: '#app',
	
	created: function(){
	 console.log('created');
   $bus.$on("chng", () => this.changeComponent());
   $bus.$on("test", () => console.log("test in test2 main/HOME"));
	},
  data() {
    return {
      currentComponent: "Test1"
    };
  },
  methods: {
    changeComponent() {
      this.currentComponent = "Test2";
    }
  }
});
<!DOCTYPE html>
<html>
<head>
	<script> console.info = function(){} </script>
	<script src="https://code.jquery.com/jquery.min.js"></script>
	<script src="https://vuejs.org/js/vue.js"></script>
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width">
	<title>Stack Overflow - Hardik Satasiya</title>
	<style>.half{width:50%;float:left;}</style>
</head>
<body>
	<div id="app">
		<component :is="currentComponent" @changeComponent="changeComponent"></component>
	</div>
</body>
</html>
0 голосов
/ 15 мая 2018

Ваш тест не верный.

Как правило, Test2Component не создается во время Test1Component испускать this.$bus.$emit("test");

Вы видели 2 console.log, потому что CodeSandbox использует модули горячей перезагрузки, поэтому this.$bus.$on("test", () => console.log("test in test2")); все еще регистрируется, если вы измените свой код.

Если вы отмените регистрацию после уничтожения компонента в Test2Component, test in test2 никогда не будет зарегистрирован

Test2Component.vue

<template>
  <div>
    <h1>test2</h1>
    <button @click="changeComponent">click me</button>
  </div>
</template>

<script>
export default {
  created() {
    console.log("Component 2 is created");
    this.$bus.$on("test", this.testLog);
  },
  beforeDestroy() {
    this.$bus.$off("test", this.testLog);
  },
  methods: {
    testLog() {
      console.log("test in test2");
    },
    changeComponent() {
      this.$emit("changeComponent");
    }
  }
};
</script>
<style>

</style>

Демо: https://codesandbox.io/s/2485jw460y

Если вы прокомментируете

  beforeDestroy() {
    this.$bus.$off("test", this.testLog);
  },

в компоненте 2 вы увидите, что test in test2 печатается много раз после нескольких нажатий

(если вы измените код, пожалуйста, обновитесь, чтобы запускаться с начала)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...