8 Vue component communication modes (Reprint)

Time:2022-1-3

This article takes you to learn more about the eight component communication modes in Vue. There is a certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

8 Vue component communication modes (Reprint)

Vue is the framework of data-driven view update, so the data communication between components is very important for Vue, so how to communicate data between components?

First of all, we need to know what kind of relationship exists between components in Vue, so that it is easier to understand their communication mode. It is like how strangers in a room call each other when they come home for the new year. At this time, we need to know what kind of relationship they have with themselves.

Relationship description in Vue component:

8 Vue component communication modes (Reprint)

1.png

As shown in the above figure, components a and B, a and C, B and D, and C and E have parent-child relationships; B and C are brothers; There is an intergenerational relationship between a and D and between a and E; D and E are cousins (not immediate relatives)
For the above relationships, we classify them as:

  • Communication between parent and child components
  • Communication between non parent and child components (sibling components, intergenerational components, etc.)

This paper will introduce 8 communication modes between components, as shown in the table of contents below: and introduce how to select effective communication modes between components in different scenarios, hoping to help partners better understand the communication between components.

8 Vue component communication modes (Reprint)

2.png

Iprops / $emit


Parent component passedpropsPass data to sub components through$emitChild components can communicate with parent components.

1. Parent component transfers value to child component

The following is an example to illustrate how the parent component passes data to the child component: in the child componentarticle.vueHow to get parent components insection.vueData inArticles: ['dream of Red Mansions',' journey to the West ',' romance of the three kingdoms']

//Section parent component
<template>
  <div>
    <com-article :articles="articleList"></com-article>
  </div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
  name: 'HelloWorld',
  components: { comArticle },
  data() {
    return {
      Articlelist: ['dream of Red Mansions',' journey to the West ',' romance of the three kingdoms']
    }
  }
}
</script>
//Subcomponent article vue
<template>
  <div>
    <span v-for="(item, index) in articles" :key="index">{{item}}</span>
  </div>
</template>

<script>
export default {
  props: ['articles']
}
</script>

Summary: prop can only be passed from the upper level component to the lower level component (parent-child component), that is, the so-called one-way data flow. Moreover, prop is read-only and cannot be modified. All modifications will be invalidated and warned.

2. The child component passes values to the parent component

about$emitMy own understanding is as follows:$emitBind a custom event. When this statement is executed, it will pass the parameter Arg to the parent component, which will listen and receive the parameters through v-on. An example is given to illustrate how the child component passes data to the parent component.
On the basis of the previous example, click the page to render itariticleofitem, the subscript displayed in the array in the parent component

//In parent component
<template>
  <div>
    <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
    <p>{{currentIndex}}</p>
  </div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
  name: 'HelloWorld',
  components: { comArticle },
  data() {
    return {
      currentIndex: -1,
      Articlelist: ['dream of Red Mansions',' journey to the West ',' romance of the three kingdoms']
    }
  },
  methods: {
    onEmitIndex(idx) {
      this.currentIndex = idx
    }
  }
}
</script>
<template>
  <div>
    <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
</template>

<script>
export default {
  props: ['articles'],
  methods: {
    emitIndex(index) {
      this.$emit('onEmitIndex', index)
    }
  }
}
</script>

II$children / $parent


8 Vue component communication modes (Reprint)

3.png

The picture above isvueOfficial interpretation, through$parentand$childrenYou can access the instance of the component. What does the instance represent? Represents all methods and that can access this componentdata。 The next step is how to get the instance of the specified component.

usage method

//In parent component
<template>
  <div>
    <div>{{msg}}</div>
    <com-a></com-a>
    < button @ Click = "changea" > Click to change sub component value < / button >
  </div>
</template>

<script>
import ComA from './test/comA.vue'
export default {
  name: 'HelloWorld',
  components: { ComA },
  data() {
    return {
      msg: 'Welcome'
    }
  },

  methods: {
    changeA() {
      //Get sub component A
      this.$children[0].messageA = 'this is new value'
    }
  }
}
</script>
//In subcomponents
<template>
  <div>
    <span>{{messageA}}</span>
    <p>Get the value of the parent component as: {{parentval}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messageA: 'this is old'
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>

Pay attention to boundary conditions, such as in#appTake it up$parentWhat you get isnew Vue()Example, take it on this example$parentWhat you get isundefined, and the sub components at the bottom$childrenIs an empty array. Also note that$parentand$childrenThe values are different,$childrenThe value of is an array, and$parentIt’s an object

summary

The above two methods are used for communication between parent and child components, and it is more common to use props for parent-child component communication; Neither can be used for communication between non parent and child components.

IIIprovide/ inject


Concept:

provide/ injectyesvue2.2.0The newly added API is simply the API passed in the parent componentprovideTo provide variables, and then pass them in the subcomponentinjectTo inject variables.

Note: no matter how deep the sub components are nested, as long as you callinjectThen you can injectprovideIt is not limited to the data that can only be returned from the props attribute of the current parent component

Example verification

Next, use an example to verify the above description:
Suppose there are three components: a.vue, b.vue and c.vue, where C is the sub component of B and B is the sub component of A

// A.vue

<template>
  <div>
    <comB></comB>
  </div>
</template>

<script>
  import comB from '../components/test/comB.vue'
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>
// B.vue

<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</template>

<script>
  import comC from '../components/test/comC.vue'
  export default {
    name: "B",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    },
    components: {
      comC
    }
  }
</script>
// C.vue
<template>
  <div>
    {{demo}}
  </div>
</template>

<script>
  export default {
    name: "C",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    }
  }
</script>

IVref / refs


ref: if it is used on an ordinary DOM element, the reference refers to the DOM element; If it is used on a sub component, the reference points to the component instance. You can directly call the component’s methods or access data through the instance. Let’s take a look at onerefTo access components:

//Sub assembly a.vue

export default {
  data () {
    return {
      name: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      console.log('hello')
    }
  }
}
//Parent component app vue

<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.name);  // Vue.js
      comA.sayHello();  // hello
    }
  }
</script>

5、 Eventbus


eventBusAlso known as event bus, it can be used as a communication bridge in Vue. It is like that all components share the same event center, and can register with the center to send or receive events, so components can notify other components.

Eventbus is also inconvenient. When the project is large, it is easy to cause disasters that are difficult to maintain

How to use it in Vue’s projectseventBusTo achieve data communication between components? The specific steps are as follows

1. Initialization

First, you need to create an event bus and export it so that other modules can use or listen to it

// event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()

2. Send event

Suppose you have two components:additionNumandshowNum, these two components can be brother components or parent-child components; Here we take brother components as an example:

<template>
  <div>
    <show-num-com></show-num-com>
    <addition-num-com></addition-num-com>
  </div>
</template>

<script>
import showNumCom from './showNum.vue'
import additionNumCom from './additionNum.vue'
export default {
  components: { showNumCom, additionNumCom }
}
</script>
// addtionNum. Send events in Vue

<template>
  <div>
    < button @ Click = "additionhandle" > + adder < / button >    
  </div>
</template>

<script>
import {EventBus} from './event-bus.js'
console.log(EventBus)
export default {
  data(){
    return{
      num:1
    }
  },

  methods:{
    additionHandle(){
      EventBus.$emit('addition', {
        num:this.num++
      })
    }
  }
}
</script>

3. Receive events

// showNum. Receive events in Vue

<template>
  < div > calculation and: {count}} < / div >
</template>

<script>
import { EventBus } from './event-bus.js'
export default {
  data() {
    return {
      count: 0
    }
  },

  mounted() {
    EventBus.$on('addition', param => {
      this.count = this.count + param.num;
    })
  }
}
</script>

In this way, the componentaddtionNum.vueClick the Add button in theshowNum.vueUsing passednumShow the result of summation

4. Remove event listener

If you want to remove event listening, you can do the following:

import { eventBus } from 'event-bus.js'
EventBus.$off('addition', {})

6、 Vuex


1. Introduction to vuex

Vuex is designed for Vue JS application development state management mode. It uses centralized storage to manage the state of all components of the application, and uses corresponding rules to ensure that the state changes in a predictable way
Vuex solved itMultiple views depend on the same stateandBehaviors from different views need to change the same stateThe problem is to focus the developer’s energy on the update of data rather than the transfer of data between components

2. Vuex modules

  • stateThe only data source used in the store is:

  • getters: like the calculation attribute in Vue, the secondary packaging based on state data is often used for data filtering and correlation calculation of multiple data

  • mutations: similar functions are the only way to change state data and cannot be used to handle asynchronous events

  • actions: similar tomutation, for submissionmutationTo change the state without directly changing the state, which can include any asynchronous operation

  • modules: similar to namespace, it is used to define and operate the status of each module separately in the project, which is convenient for maintenance

3. Vuex instance application

//Parent component

<template>
  <div>
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
  import ChildA from './ Components / childa '// import component A
  import ChildB from './ Components / childb '// import component B

  export default {
    name: 'App',
    Components: {childa, childb} // register components a and B
  }
</script>
//Sub assembly childa

<template>
  <div>
    <h1>I'm component A</h1>
    < button @ Click = "transform" > Click to let component B receive data < / button >
    <p>Because you ordered B, my information changed: {{bmessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        Amessage: 'Hello, component B, I'm component a'
      }
    },
    computed: {
      BMessage() {
        //The data of the B component obtained from the store is stored here
        return this.$store.state.BMsg
      }
    },
    methods: {
      transform() {
        //Trigger receiveamsg to store the data of component A in the store
        this.$store.commit('receiveAMsg', {
          AMsg: this.AMessage
        })
      }
    }
  }
</script>
//Sub assembly childb

<template>
  <div>
    <h1>I'm component B</h1>
    < button @ Click = "transform" > Click to let component a receive data < / button >
    <p>Because you ordered a, my information changed: {{amessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        Bmessage: 'Hello, component A, I'm component B'
      }
    },
    computed: {
      AMessage() {
        //The data of component a obtained from the store is stored here
        return this.$store.state.AMsg
      }
    },
    methods: {
      transform() {
        //Trigger receivebmsg to store the data of component B in the store
        this.$store.commit('receiveBMsg', {
          BMsg: this.BMessage
        })
      }
    }
  }
</script>

Vuexstore,js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
  //Initialize the data of components a and B and wait for acquisition
  AMsg: '',
  BMsg: ''
}

const mutations = {
  receiveAMsg(state, payload) {
    //Store the data of component A in state
    state.AMsg = payload.AMsg
  },
  receiveBMsg(state, payload) {
    //Store the data of component B in state
    state.BMsg = payload.BMsg
  }
}

export default new Vuex.Store({
  state,
  mutations
})

VIIlocalStorage / sessionStorage


This kind of communication is relatively simple. The disadvantage is that the data and state are chaotic and not easy to maintain.

adoptwindow.localStorage.getItem(key)get data

adoptwindow.localStorage.setItem(key,value)Store data

Pay attention to useJSON.parse() / JSON.stringify()Do data format conversion
localStorage / sessionStorageCan combinevuex, realize the persistent preservation of data, and use vuex to solve the problem of data and state confusion

eight$attrsAnd$listeners


Now let’s discuss a situation. In the component diagram given at the beginning, component A and component D are inter generational. What are the ways they communicate before?

  • usepropsBinding is used for level-by-level information transmission. If the state of D component needs to be transmitted to a, the event system is used for level-by-level information transmission

  • useeventBus, it is still suitable for use in this case, but when it comes to multi person cooperative development, the code maintainability and readability are low

  • Vuex is used for data management, but if you only transfer data without intermediate processing, it feels a little overqualified to use vuex processing

stayvue2.4In order to solve this requirement, the$attrsand$listeners, newinheritAttrsOptions. Before version 2.4, by default, feature bindings (except class and style) that are not recognized (and obtained) as props in the parent scope will be “fallback” and applied to the root element of the child component as ordinary HTML features. Next, let’s look at an example of cross level communication:

// app.vue
// index.vue

<template>
  <div>
    <child-com1
      :name="name"
      :age="age"
      :gender="gender"
      :height="height"
     
    ></child-com1>
  </div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
  components: { childCom1 },
  data() {
    return {
      name: "zhang",
      age: "18",
      Gender: "female",
      height: "158"
    };
  }
};
</script>
// childCom1.vue

<template>
  <div>
    <p>name: {{ name}}</p>
    <p>$attrs for childcom1: {{$attrs}}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
  components: {
    childCom2
  },
  Inheritattrs: false, // you can turn off the attributes not declared in props that are automatically mounted on the component root element
  props: {
    Name: string // name is bound as props attribute
  },
  created() {
    console.log(this.$attrs);
     //{"age": "18", "gender": "female", "height": "158", "title": "programmer growth points north"}
  }
};
</script>
// childCom2.vue

<template>
  <div>
    <p>age: {{ age}}</p>
    <p>childCom2: {{ $attrs }}</p>
  </div>
</template>
<script>

export default {
  inheritAttrs: false,
  props: {
    age: String
  },
  created() {
    console.log(this.$attrs); 
    //{"gender": "female", "height": "158", "title": "programmer growth points north"}
  }
};
</script>

For more programming related knowledge, please visit:Programming video!!

Recommended Today

Vue2 technology finishing 3 – Advanced chapter – update completed

3. Advanced chapter preface Links to basic chapters:https://www.cnblogs.com/xiegongzi/p/15782921.html Link to component development:https://www.cnblogs.com/xiegongzi/p/15823605.html 3.1. Custom events of components 3.1.1. Binding custom events There are two implementation methods here: one is to use v-on with vuecomponent$ Emit implementation [PS: this method is a little similar to passing from child to parent]; The other is to use ref […]