Eight communication modes of Vue

Time:2022-1-19
1.props / emit
  1. Parent component passes value to child component
    The following is an example to illustrate how the parent component passes data to the child component: in the child component article How to get the parent component section in Vue Data articles in Vue: [‘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.

  1. Child component passes value to parent component
    Emit binds a custom event. When this statement is executed, it will pass the parameter Arg to the parent component, which listens and receives 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 item of ariticle rendered on the page, and 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>
//In subcomponents
<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>
2、 Children / parents

Eight communication modes of Vue

The picture above is Vue official explanation, throughparent/childrenYou can access the instance of the component. What does the instance represent? Represents all methods and data that can access this component. 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 the boundary, such as taking it on #app

  • The immediate child component of the current instance. Need attentionChildren for data binding, consider using an array with V-for to generate sub components, and using array as the real source.
  • The root Vue instance of the current component tree. If the current instance does not have a parent instance, the instance will be its own.
  • $children is an array, which is a collection of direct sons. For the specific sons, there is one in the sons_ Uid attribute, we can know which element it is and the unique identifier of the element. According to this attribute, we can carry out other operations
3、 Provide / inject

Concept:
provide/ injectyesvue2.2.0NewapiIn short, it means that the parent componentprovideTo provide variables, and then inject variables into sub components through inject.

Note: no matter how deep the sub components are nested, as long as you callinjectThen you can injectprovideThe data in is not limited to the data from the current parent componentpropsData in attribute

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>

4、 Ref / 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 an example of ref accessing the component:

//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、 Event / bus

Eventbus, also known as event bus, can be used as a communication bridge in Vue. It is like that all components share the same event center, which can register 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 eventbus to realize data communication between components in Vue’s project? 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: additionnum and shownum. 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 component addionnum Click the Add button in Vue to show num In Vue, the sum result is displayed by using the passed num

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 solves the problem that multiple views depend on the same state and the behavior from different views needs to change the same state, and focuses the developer’s energy on the update of data rather than the transmission of data between components

2. Vuex modules

  • State: used for data storage. It is the only data source in the store
  • 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, the only way to change state data, and cannot be used to handle asynchronous events
  • Actions: similar to mutation, it is used to submit a mutation to change the state without directly changing the state. It can include any asynchronous operation
  • Modules: similar to namespaces, it is used to define and operate the status of each module separately in the project for easy maintenance

3. Vuex instance application

//Parent component
 
<template>
  <div>
    <ChildA />
    <ChildB />
  </div>
</template>
 
<script>
import ChildA from "./components/ChildA"; //  Import a component
import ChildB from "./components/ChildB"; //  Import B components

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>

Vuex’s store, 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
})
7、 Localstorage / 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 storage of data, and usevuexSolve the problem of data and state confusion

Eight attrs and 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?

Props binding 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
In vue2 4, in order to solve this requirement, theAttrs and listeners, the inheritattrs option has been added. 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>

summary
Common usage scenarios can be divided into three categories:

Parent child component communication: props; parent / children; provide / inject ; ref ; attrs / listeners
Brother component communication: eventbus; vuex
Cross level communication: eventbus; Vuex; provide / inject 、attrs / listeners