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
- 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.
- The EventBus life cycle is triggered only once.
- EventBus needs to be initialized and destroyed each time a business page is opened and closed.
- 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/…