EventBus is a common component communication method in Vue2, which solves the communication and data sharing problems among multiple components

Here’s a typical example

A business page

<template>
  <div>
    <! -- Component A -->
    <component-a></component-a>
    <! -- Component B -->
    <component-b></component-b>
  </div>
</template>

<script>
import EventBus from "./eventBus.js";

export default {
  created() {
    EventBus.init(); / / initialization
  },

  beforeDestroy() {
    EventBus.destroy(); / / destroy}};</script>
Copy the code

EventBus.js

import Vue from "vue";

export default new Vue({
  data() {
    return {
      loading: false.listData: null
    };
  },

  methods: {
    / / initialization
    init() {
      this.destroy();
      this.loadData();
    },

    / / destroy
    destroy() {
      this.loading = false;
      this.listData = null;
    },

    / / access number
    loadData() {
      this.loading = true;

      // Get data through the interface
      / /...
      this.listData = [/* Business data... * /]; }}});Copy the code

Component A

<template>
  <div v-if="dataLoading">Chrysanthemum turned...</div>
  <div v-else>
    <! -- Business code -->
  </div>
</template>

<script>
import EventBus from "./eventBus.js";

export default {
  computed: {
    dataLoading() {
      return EventBus.loading;
    },

    listData() {
      returnEventBus.listData; }}};</script>
Copy the code

Looking at the appellate code, there are several problems

  1. The EventBus is loaded whenever the business page is open, and when the business page is closed, the EventBus will still exist and will not be destroyed when the business page is closed, which will undoubtedly take up some memory.
  2. The EventBus life cycle is triggered only once.
  3. EventBus needs to be initialized and destroyed each time a business page is opened and closed.
  4. In some business scenarios, EventBus does not need to be created immediately and is only used under certain conditions.

How to solve it?

The first, second, and third problems are easier to solve by creating the EventBus as a function and then providing the business page to the child components as an injection.

eventBus.js

Business page

Child components

However, this scheme has a big disadvantage. It can only be used by parent-child components, but not by horizontal components. Moreover, the fourth problem cannot be solved

Better solutions

Encapsulate an EventBus that creates lazy loading and uses proxy to intercept property access

createLazyEventBus.js

import Vue from "vue";

const destroyFunctionName = "destroy";

/** * Create lazy load EventBus *@param {*} config
 * @returns* /
export default function createLazyEventBus(config) {
  let instance = null;

  // Destruct function
  function destroy() {
    instance.$destroy();
    instance = null;
  }

  return new Proxy({}, {get() {
        const key = arguments[1];

        if(! instance) { instance =new Vue(config);
        }

        if( key === destroyFunctionName && ! instance.hasOwnProperty(destroyFunctionName) ) {return destroy;
        }

        return Reflect.get(instance, key); }}); }Copy the code

Transform the EventBus. Js

eventBus.js

import createLazyEventBus from "vue";

export default createLazyEventBus({
  data() {
    return {
      loading: false.listData: null
    };
  },

  // The initialization code can be written directly to the lifecycle function, and is automatically called
  created() {
    this.loadData();
  },

  methods: {
    / / access number
    loadData() {
      this.loading = true;

      // Get data through the interface
      / /...
      this.listData = [
        /* Business data... * /]; }}});Copy the code

The business page impor EventBus into the component the way it was originally, but there is no need to call init manually, and EventBus is only actually initialized when it is used by the child component!

Business page

<template>
  <div>
    <! -- Component A -->
    <component-a></component-a>
    <! -- Component B -->
    <component-b></component-b>
  </div>
</template>

<script>
import EventBus from "./eventBus.js";

export default {
  created() {
    // EventBus.init(); You don't need to call init manually
  },

  beforeDestroy() {
    EventBus.destroy(); // Manual destruction is required}};</script>
Copy the code

Child components

<template>
  <div v-if="dataLoading">Chrysanthemum turned...</div>
  <div v-else>
    <! -- Business code -->
  </div>
</template>

<script>
import EventBus from "./eventBus.js";

export default {
  computed: {
    dataLoading() {
      return EventBus.loading;
    },

    listData() {
      returnEventBus.listData; }}};</script>
Copy the code

conclusion

The EventBus mode for component communication is no longer needed in Vue3, but some of the ideas need to be remembered, such as using EventBus to design the system’s EventBus. Lazy loading is not often used in daily work, but it is of great help for performance optimization. There are many ways to implement it, such as Proxy used in this article, closure or class GET, etc. We need to flexibly choose the appropriate implementation scheme according to the actual situation.

Knowledge link

[MDN] Proxy document developer.mozilla.org/zh-CN/docs/…