As you know, one of the main ideas of Vue is component development. Therefore, in the actual project development, will certainly be carried out in the component development mode. Just as pages need to communicate with each other, Vue components need to communicate and share state with each other. Next, we will show you how all Vue components communicate with each other.

Relationship between components








  • Components A and B, B and C, and B and D form A parent-child relationship
  • Components C and D form a sibling relationship
  • Components A and C, and components A and D form an intergenerational relationship (where the hierarchy may be multilevel, i.e., intergenerational).

Component communication

With so many component relationships, what are the ways in which components communicate with each other? What’s the difference? What are the applicable scenarios? Keep reading with questions!

1.props$emit

This combination will be familiar to any developer who has worked on a Vue stack development project, and it is one of the many ways we use component communication. Props can communicate with parent and child components in the form of one-way data flow.

Unidirectional data flow: Data can be transmitted from the parent component to the child component only through props. The child component cannot change the state of the parent component by modifying the data transmitted by props. As for why, the Vue website explains:

All prop forms a one-way downlink binding between their parent prop: updates to the parent prop flow down to the child, but not the other way around. This prevents accidental changes in the state of the parent component from the child, which can make the data flow of your application difficult to understand. Additionally, every time the parent component is updated, all prop in the child component will be refreshed to the latest value. This means that you should not change a prop inside a child component. If you do, Vue will issue a warning in the browser console. – Vue website

Because of this feature, there is a corresponding $emit. $emit is used to trigger events on the current instance. We can do this by customizing a logic in the parent that handles accepting the changed state, and then triggering the parent’s logic to handle the event when the relevant state changes in the child.

/ / the parent component
Vue.component('parent', {
  template:` 
      

this is parent component!

`
, data() { return { message: 'hello'}},methods: {// Executes the event triggered by the child component getChildData(val) { console.log(val); }}});/ / child component Vue.component('child', { template:`
`
./** * props: {* message: {* type: String, * default: '' *} *} * */ props:['message'], data() { return { // This is necessary because you cannot modify the props value directly myMessage: this.message } }, methods:{ passData(val) { // Events in the parent component are triggered when the data state changes this.$emit('getChildData', val); }}});var app=new Vue({ el: '#app'.template: `
`
}); Copy the code

In the example above, we have a parent component and a child component.

  • 1) The parent component passes the message data to the child component, and uses v-ON to bind a getChildData event to listen for the child component’s trigger event;
  • $this.$emit (); / / This.$this.$emit (); / / this.

2,$attrs$listeners

The above method of component communication is only suitable for direct parent components, that is, if parent component A has child component B under, component B has component C under, then if component A directly wants to pass data to component C, it will not work! Component A can only use props to transmit data to component B, and then component B can use props to transmit data to component C. Of course, this way is very complex, irrelevant components in a logical business increased, code maintenance has not become difficult, plus if the more nested hierarchies logic is also complex, the more irrelevant code!

To address this problem, Vue 2.4 provides $listeners and $Listeners to enable component A to pass messages directly to component C.

/ / component A
Vue.component('A', {
  template: ` 
      

this is parent component!

`
, data() { return { message: 'hello'.messagec: 'hello c' // The data passed to the C component}},methods: { // Execute the event triggered by the B child getChildData(val) { console.log('Here's the data from component B:${val}`); }, // Executes the event triggered by the C child component getCData(val) { console.log('Here's the data from the C component:${val}`); }}});/ / component B Vue.component('B', { template: ` <div> <input type="text" v-model="mymessage" @input="passData(mymessage)"> <! Note That $Listeners are now calling getCData on notice because the listeners are using V -> <! -- Bind the $attrs attribute with v-bind, <C v-bind="$attrs" v-on="$listeners"></C> </div./** * props: {* message: {* type: String, * default: '' *} *} * */ props: ['message'], data(){ return { mymessage: this.message } }, methods: { passData(val){ // Triggers events in the parent component this.$emit('getChildData', val) } } }); C / / component Vue.component('C', { template: `
`
.methods: { passCData(val) { // Triggers events in parent component A this.$emit('getCData',val) } } }); var app=new Vue({ el:'#app'.template: ` ` }); Copy the code

In the example above, we define components A, B, and C, where component B is A child of component A and component C is A child of component B.

  • 1). In component A, define A property value (Message, Messagec) and A listening event (getChildData, getCData) for component B and C respectively, and pass these to A direct subcomponent B of component A via props;
  • 2). In component B, props obtains only the properties directly related to itself (message), and caches the property values in data so that subsequent changes can be monitored for processing. Then, when the property values change, the data logic processing event defined by parent component A (getChildData) is triggered. Component C, a direct child of component B, passes properties$attrsAnd bind events$listeners;
  • 3). It is directly bound to the V-Model in component C$attrsProperty, bound by V-ON$listeners;

Note $listeners and $attrs separately.

  • $attrs: contains property bindings (except class and style) in the parent scope that are not recognized (and retrieved) by prop. When a component does not declare any prop, it contains all the binding properties of the parent scope (except class and style) and can be passed in to the internal component with v-bind=”$attrs”.

  • $Listeners: Contains V-on event listeners in the parent scope (without.native modifiers). It can be passed into internal components via V-on =”$Listeners “.

3. Central EventBus EventBus

For the communication between parent and child components, the above two ways are completely possible, but for the two components are not the parent relationship, so how to achieve communication? For small projects, it is perfectly possible to use the central EventBus EventBus. If your project is medium to large, you can use Vuex state management, which we will cover later.

EventBus creates a Vue EventBus object and emits events via bus.$on.

/ / component A
Vue.component('A', {
  template: ` 
      

this is A component!

`
, data() { return { mymessage: 'hello brother1'}},methods: { passData(val) { // trigger the globalEvent globalEvent this.$EventBus.$emit('globalEvent', val) } } }); / / component B Vue.component('B', { template:`

this is B component! < / p > < p > component A passed data: {{brothermessage}} < / p > < / div > `

, data() { return { mymessage: 'hello brother2'.brothermessage: ' ' } }, mounted() { // bind the globalEvent globalEvent this.$EventBus.$on('globalEvent', (val) => { this.brothermessage = val; }); }});// Define the central event bus const EventBus = new Vue(); // Assign the central event bus to vue. prototype so that all components can access it Vue.prototype.$EventBus = EventBus; const app = new Vue({ el: '#app'.template: ` ` }); Copy the code

In the example above, we define components A and B, but there is no relationship between components A and B.

  • 1) First we passnew Vue()Instantiate an instance of Vue, which we call the central EventBus EventBus, and assign it toVue.prototype.$EventBusTo make all business logic components accessible;
  • 2), then define component A, in the component A definition of A processing method passData, mainly defined to trigger A globalglobalEventEvent and passes a parameter;
  • 3). Finally define component B, inside component BmountedThe lifecycle listens for globals defined in component AglobalEventEvent and performs some logical processing inside the callback function.

A central EventBus (EventBus) is a simple way to interact with any component. There is no extra business logic. You only need to trigger an event in the state-changing component and then listen for that event in the processing logic component. This method is perfect for small projects!

4,provideinject

React development Context API is familiar to you. A similar API is provided in Vue for communication between components.

Properties are provided by providers in the parent component and variables are injected by inject in the child component. Instead of being limited to fetching data from the prop property of the current parent component, the child component can be called as long as it is in the life of the parent component. React Context API!

// Define the parent component
Vue.component('parent', {
  template: ` 
      

this is parent component!

`
.provide: { for:'test' }, data() { return { message: 'hello'}}});// Define the child component Vue.component('child', { template: `
`
.inject: ['for'].// Get the data from the parent component data(){ return { mymessage: this.for } }, }); const app = new Vue({ el: '#app'.template: `
`
}); Copy the code

In the example above, we define component parent and component child, and component parent and component child are parent-child relationships.

  • 1), inparentComponent, throughprovideProperties, which expose properties to descendant components in the form of objects
  • 2), inchildComponent, throughinjectProperty injectedparentThe component provides the data that actually passes theseinjectInjected properties are mounted to the Vue instance, so they can be accessed from within the component via this.

⚠️ Note: The official website documents mention provide and inject mainly provide use cases for high-level plug-ins/component libraries and are not recommended to be directly used in application code.

See the documentation on the official website for more details on the use of the provide and Inject attributes.


I’m a little tired of writing here. The four ways that Vue components communicate have been outlined. Do you think that’s enough? No, no, no. There are four more ways to go after the first four! Use this to add a dividing line, pressure! 😭 right, do not say to learn immovable, as long as there is a breath, to continue learning!


5,v-model

This is a bit like props, but it certainly has its own props too! Anyway, code first!

// Define the parent component
Vue.component('parent', {
  template: ` 
      

this is parent component!

{{message}}

`
, data() { return { message: 'hello'}}});// Define the child component Vue.component('child', { template: `
`
.props: { value: String.// The V-model will automatically pass a props property with a field value }, data() { return { mymessage: this.value } }, methods: { changeValue() { this.$emit('input'.this.mymessage); // This call changes the value of the V-Model binding on the parent component}}});const app = new Vue({ el: '#app'.template: `
`
}); Copy the code

When you think of the V-model specification, you probably think of two-way data binding, such as the input value, and the following display displays the content based on the input in real time. Did you feel magical when you first learned Vue? No matter you did, I had this feeling!

For detailed v-Model usage and implementation of the custom component V-Model, go here! Here we focus on how the V-Model implements parent-child component communication.

In the example code above, we define the parent and child components, which are parent-child relationships, and the V-Model can only communicate between parent and child components.

  • 1) In the parent component, we implement the v-model binding of message property for the user-defined Child component. This is equivalent to passing the value attribute to the Child component and binding the input event.
  • 2) In the child component, the props can be used to obtain the value property, and the value is caged on myMessage of the data, and then passed on the inputv-modelThe bindingmymessageProperties and achangeEvents. When the input value changes, the change event is raised to process the parent component throughv-modelBound to the Child componentinputEvent, triggerparentIn the componentmessageProperty value change, donechildThe child component changes the property value of the parent component.

Here is mainly the realization principle of V-Model to focus on understanding! This approach is useful for separating presentation components from business logic components.

6,$parent$children

The way to do this is fairly straightforward: directly manipulate instances of parent and child components. $parent is an instance of the parent component, and $children is a direct child of the current instance, but the value is array, not sequential, and not reactive.

// Define the parent component
Vue.component('parent', {
  template: ` 
      

this is parent component!

`
, data() { return { message: 'hello'}},methods: { changeChildValue(){ this.$children[0].mymessage = 'hello'; }}});// Define the child component Vue.component('child', { template:`
`
, data() { return { mymessage: this.$parent.message } }, methods: { changeValue(){ this.$parent.message = this.mymessage;// The value of the parent component can be changed by this call}}});const app = new Vue({ el: '#app'.template: `
`
}); Copy the code

In the example code above, we define the parent and Child components, which are directly parent-child. Each component defines its own attributes internally. $this.$children[0]. Mymessage = ‘hello’; The parent component communicates with the parent component by assigning the myMessage attribute to the child component and the parent component’s message to the this.$parent. Message.

The $parent and $children attributes can be found in the documentation.

7,$boradcast$dispatch

This also came in pairs, but it was only available in VU1.0, which was deprecated in Vu2.0, but there are many open source software packages that encapsulate this way of component communication, such as Mint UI, Element UI, and iView.

// The main logical processing method of the broadcast method
function broadcast(componentName, eventName, params) {
  this.$children.forEach(child= > {
    const name = child.$options.componentName;

    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else{ broadcast.apply(child, [componentName, eventName].concat(params)); }}); }export default {
  methods: {
    // Define the dispatch method
    dispatch(componentName, eventName, params) {
      let parent = this.$parent;
      let name = parent.$options.componentName;
      while(parent && (! name || name ! == componentName)) { parent = parent.$parent;if(parent) { name = parent.$options.componentName; }}if(parent) { parent.$emit.apply(parent, [eventName].concat(params)); }},// Define the broadcast method
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params); }}};Copy the code

Broadcast triggers events to a specific parent component, dispatch triggers events to a specific child component, and is essentially an ON/EMIT wrapper, which is useful in some basic components.

Since this API was deprecated in Vue 2.0, we will mention it here. If you want to learn more about the implementation of this API in Vue 1.0 and other Vue based UI frameworks, you can check out this article!

Vuex state management

Vuex is a status management tool that enables centralized management of project status. The implementation of The tool borrows patterns and concepts from Flux, Redux, and The Elm Architecture. Unlike other patterns, Vuex is a state management library designed specifically for vue.js to leverage the fine-grained data response mechanism of vue.js for efficient state updates. For a detailed introduction to Vuex, you can check out the documentation on the official website or check out the series of introductions to Vuex in this column.

conclusion

Now that I’ve covered all the ways in which components can communicate in Vue, isn’t that a bit overwhelming? In fact, there are two other ways to communicate components. One is through the Vue Router, and the other is through the browser local storage. I won’t talk about these two methods here, but I will explain them separately in this column, which I hope you are interested in.

To be precise, this article details six ways to implement Vue communication, each of which has its own characteristics. In the actual project, you can use it as appropriate.