Event Bus-EventBus Differences and Detailed Usage in Vue2/3

Vue event bus

The event bus essentially solves the communication problem between various components.

To solve the value transfer/communication between components with different hierarchical relationships, the current common methods are:

  • In the project, there are multi-layer component parameters that can be used $attrs, which can make the code more beautiful, more concise, and more convenient when maintaining the code;
<!-- Father.vue -->
<template>
  <!-- 给子组件传了两个参数,但是子组件没有用prop接收-->
  <child-comp :is-show="isOpen" :row="row"></child-comp>
</template>

<!-- Child.vue -->
<template>
  <div class='child-view'>
    <p>子组件</p>
    <GrandChild v-bind="$attrs"></GrandChild>
  </div>
</template>
<script>
import GrandChild from './GrandChild.vue'
export default {
      
      
  // 继承所有父组件的内容
  inheritAttrs: true,
  components: {
      
       GrandChild }
}
</script>

<!-- Grand.vue -->
<template>
  <div class='grand-child-view'>
    <p>孙子组件</p>
    <p>传给孙子组件的数据:{
   
   {row.name}} {
   
   {row.name !== undefined? '学习' : ''}} {
   
   {row.study}}</p>
  </div>
</template>

<script>
export default {
      
      
  // 不想继承所有父组件的内容,同时也不在组件根元素dom上显示属性
  inheritAttrs: false,
  // 在本组件中需要接收从父组件传递过来的数据,注意props里的参数名称不能改变,必须和父组件传递过来的是一样的
  props: {
      
      
    isShow: {
      
      
      type: Boolean,
      dedault: false
    },
    row: {
      
      
      type: Object,
      dedault: () => {
      
       }
    }
  }
}
</script>

(If the data passed to the component is not received by the component using props, then these data will be used as the properties of the HTML element of the component, and these properties are bound to the HTML root element of the component)

  • Between components with complex relationships, it will be cumbersome to pass parameters using ordinary parent-child components prop, especially in the case of sibling components and ancestor-descendant components.$emit$on
  • If you use it, vuexit will be overkill. It is only used in these components, and it is not necessary to use it vuex; and vuexit is used for data state storage. If it is used for state transfer, this kind of statedata will be very redundant.
  • Use dependency injection ( provideand inject).
  • Event bus EventBus .

event bus

eventBusIt is a very simple but practical solution, suitable for cross-level components to pass messages. I often use this method in projects. I recommend it. You can learn about this method. [It should be noted that if the event bus is used eventBusimproperly, the event may be executed multiple times .

The following are the implementations of the event bus in Vue2 and Vue3 respectively .

Event bus in Vue2

// common/event-bus.js
import Vue from 'vue'
const EventBus = new Vue()
export const EventBridge = {
    
    
  eventName: {
    
    
  	closeLabel: 'closeLabel',
    openLabel: 'openLabel',
    showDetailLabel: 'showDetailLabel'
  },
  on(name, fn) {
    
    
  	EventBus.$on(name, fn)
  },
  emit(name, data) {
    
    
  	EventBus.$emit(name, data)
  },
  offOne(name) {
    
    
  	EventBus.$off(name)
  },
  // 移除所有的时间监听
  offAll() {
    
    
  	EventBus.$off()
  },
  getEventName(key, value) {
    
     // value是没有取到值时的默认值
  	return this.eventName[key] + value
  }
}

Instructions:

// a.vue
<script>
import {
    
     EventBridger } from '@/common/event-bus'
export default {
    
    
  methods: {
    
    
  	showDetail(data) {
    
    
      EventBridger.emit('showDetailLabel', data)
    }
  }
}
</script>

// b.vue
<script>
import {
    
     EventBridger } from '@/common/event-bus'
export default {
    
    
  mounted() {
    
    
    EventBridger.on('showDetailLabel', (data) => {
    
    
      this.handlerShowDetai(data)
    })
  },
  methods: {
    
    
    handlerShowDetai(data) {
    
    
      console.log(data)
    }
  }
}
</script>

[Method 2. Mount the event bus to the global instance app]

// main.js
Vue.prototype.$EventBus = new Vue()
new Vue({
    
    
  router,
  store,
  render: h => h(App)
}).$mount('#app')

Instructions:

// a.vue
this.$EventBus.$emit('abc')

// b.vue
mounted() {
    
    
  this.$EventBus.$on('abc, (data) => {
    
    
    console.log(data)
	// do your things
  })
}

[Method 3]
In Method 2, we created an empty Vue object to be used as an event bus and mounted it on our global application property.
Maybe we can make it even simpler. The same is true
for direct use of this.$root.$emitand , and one less Vue object can be initialized.this.$root.$on

Event bus in Vue3

In the version of Vue3.0+, Vue removed $onthe , $offand $oncemethods ; and did not provide compatible functions. See the description of the document for details

insert image description here

In Vue3, the event bus mode can be replaced by using an external library that implements the event trigger interface, such as mitt or tiny-emitter , which is the officially recommended event bus replacement.

// eventBus.js
import emitter from 'tiny-emitter/instance'

export default {
    
    
  $on: (...args) => emitter.on(...args),
  $once: (...args) => emitter.once(...args),
  $off: (...args) => emitter.off(...args),
  $emit: (...args) => emitter.emit(...args),
}

It provides the same event trigger API as Vue 2.

In most cases, the use of a global event bus for communication between components is discouraged. While often the easiest solution in the short term, it's always a headache to maintain in the long run. Depending on the situation, there are various alternatives to the event bus:

  • Props and events should be the first choice for communication between parent and child components. Sibling nodes can communicate through their parent nodes.
  • Provide and inject allow a component to communicate with the contents of its slots. This is useful for tightly coupled components that are always used together.
  • provide/inject can also be used for long distance communication between components. It can help avoid "prop pass-through", where props need to be passed down through many layers of components, but those components may not themselves need those props.
  • Prop passthrough can also be avoided by refactoring to use slots. If an intermediate component does not require certain props, it may have a separation of concerns problem. Using a slot in this type of component allows the parent node to directly create content for it, so props can be passed directly without the participation of intermediate components.
  • Global state management, such as Vuex.

further reading

Note about the use of provide and inject:

However, there are downsides to dependency injection. It couples the components in your application to how they are currently organized, making refactoring much harder. Also the provided property is non-responsive. This is by design, as using them to create a centrally scaled data is not good enough to do it with $root. If the property you want to share is specific to your application and not generalized, or if you want to update provided data in an ancestor component, then this means that you may need to switch to a real one like Vuex state management scheme.

Solve the responsive problem of provide and inject

provide/injectBindings are not reactive by default . This is embarrassing.

However, in Vue2, we can pass in a listenable object, so the object's propertyis still responsive.

What are listenable objects?
Listenable response objects: Array, Object.

Alternatively, in Vue3, we can make it reactive by passing a ref propertyor reactiveobject to provideit .

provide() {
    
    
    return {
    
    
      todoLength: Vue.computed(() => this.todos.length)
    }
}

To provideincrease injectthe responsiveness between and values, we providecan use refor when the value reactive.

setup() {
    
    
  const location = ref('North Pole')
  const geolocation = reactive({
    
    
    longitude: 90,
    latitude: 135
  })
  provide('location', location)
  provide('geolocation', geolocation)
}

When using reactive provide / injectvalues , it is recommended to propertylimit all modifications to the reactive to within the providedefined component as much as possible.

// 提供 provide 的组件
methods: {
    
    
    updateLocation() {
    
    
      this.location = 'South Pole'
    }
}

However, sometimes we need injectupdated . In this case, we propose providea method responsible for changing the responsiveness property.

[The parent component itself provides a method that can change the property, and providewhen it comes out, the descendant components call this method to modify it property.

const updateUserLocation = inject('updateLocation')

Finally, we recommend the use if you want to ensure that data providepassed through won't be changed by components of .injectpropertyreadonly

provide('location', readonly(location))

—————————— [End of text] ——————————

Front-end learning exchange group, if you want to come in face-to-face, you can join the group: 685486827 , 832485817 ;
Vue learning exchange React learning exchange

Written at the end: convention is better than configuration - the principle of simplicity in software development

—————————— 【End】 ——————————

My:
Personal website: https://neveryu.github.io/neveryu/
Github: https://github.com/Neveryu
Sina Weibo: https://weibo.com/Neveryu
WeChat: miracle421354532

For more learning resources, please pay attention to my Sina Weibo... ok

Guess you like

Origin blog.csdn.net/csdn_yudong/article/details/121982548