Six ways of communication between vue components
1. props and $emit (child triggers parent), ref (parent calls child)
- The props keyword is generally used to transfer data from the parent component to the child component.
- The child component passes data to the parent component. Generally, $emit is used to trigger the event of the parent component; Because the child component cannot directly modify the value in props (i.e. the value passed by the parent component), if it needs to be modified, the parent component should be informed to modify by triggering the event of the parent component.
- The parent component directly calls the method of the child component. You can get the instance of the child component with $refs to call its method.
The example code is as follows:
// Parent.vue <template> <div> <span>I am Parent assembly</span> <Child ref="child" :parentValue="value" @emitEdit="edit"></Child> </div> </template> <script> import Child from "./Child.vue"; export default { components: { Child }, data() { return { value: "I am the parent component" } }, methods: { pFn() { console.log("I am the parent component's method"); // Method of calling subcomponent this.$refs.child.cFn(); }, // The subcomponent triggers and modifies the value of value edit(msg) { this.value = msg; } } } </script>
// Child.vue <template> <div> <span>I am Child assembly</span> <span>Value passed by parent component:{{this.parentValue}}</span> <button @click="editParentValue">modify parentValue</button> </div> </template> <script> export default { props: { parentValue: String }, methods: { cFn() { console.log("I am a subcomponent method"); } editParentValue() { this.$emit("emitEdit", "The subcomponent modified me"); } } } </script>
2,Event Bus(\(on,\)emit)
- Event Bus mode is mainly used to transfer values between components without parent-child relationship, such as brother components
- Register listening events with $on in component A and trigger events with $emit in component B
The example code is as follows:
// Create a vue instance as the event bus; It can be registered on the global or vue's prototype vue.propotype.eventBus = new Vue();
// CompA.vue <template> <div> <span>I am CompA assembly</span> <span>value Value of:{{ value }}</span> </div> </template> <script> export default { data() { return { value: "I am CompA assembly" } }, mounted() { this.eventBus.$on("edit", (msg) => { this.value = msg; }) } } </script>
// CompB.vue <template> <div> <span>I am CompB assembly</span> <button @click="editValue">modify CompA of value</button> </div> </template> <script> export default { methods: { editValue() { this.eventBus.$emit("edit", "CompB Modified me"); } } } </script>
Question: why not use this\ (emit and this.\)on, and new an empty vue instance?
3. provide and inject
- The provide and inject methods are usually used for communication between grandparent and grandparent components, and are mainly used to transfer values from the grandparent component to the child component
- provide is used to define properties or methods that can be injected into child components in the ancestor component
- Inject is used to inject dependencies such as attributes and methods into sub components
Example code:
// CompA.vue <template> <div> <span>I am CompA assembly</span> <span>value Value of:{{ value }}</span> <!--Among them, CompA Components are not necessarily CompB The direct parent of the component, or CompB The ancestor component of a component. There can be multiple component references in the middle--> <CompB ref="compB"></CompB> </div> </template> <script> import CompB from "./CompB.vue"; export default { components: { CompB }, data() { return { value: "I am CompA assembly" } }, provide() { return { // Expose these two variables outward aValue: this.value, aFn: this.fn } }, // Using Vue Observable () can make the value passed by provide responsive, that is, after modification in the ancestor component, the value in the child component will change synchronously provide() { this.aData = Vue.observable({ value: this.value, aFn: this.fn }); return { aData: this.aData }; }, methods: { fn() { console.log("I am CompA Method of"); } } } </script>
// CompB.vue <template> <div> <span>I am CompB assembly</span> <button @click="aFn">call CompA of fn</button> </div> </template> <script> export default { // Injection dependency inject: ["aValue", "aFn"], mounted() { console.log("CompA Component value", this.aValue); } } </script>
4. $parent and $children
- $parent and $children are used for communication between components with direct parent-child relationship
- $parent is used to get the parent component instance of the component
- $parent is used to get the sub component instance of the component
5. $attrs and $listeners
- $attrs and $listeners are mainly used to obtain the properties and methods of the parent component
- $attrs is used to get the attributes in the parent component that are not received in the props of the child component
- $listeners is used to get custom events in the parent component
6,Vuex
Vuex is similar to a warehouse. It can store some data for global call, but the refresh page will disappear. To solve this problem, you can choose to store the data in sessionStorage or localStorage while storing it in vuex.
Vuex includes state, changes, actions, getters, and modules. among
- state: define variables
- getters: get the value of the variable in state
- Changes: modify the value in state; Use commit to trigger; Only synchronization can be performed
- actions: perform various operations, which can be triggered through dispatch; Asynchronous operation is possible
- modules: when the project is large, you can split the variable management into multiple js files, each js file as a single module, and then uniformly register it in index js for global call
Example code:
// module.js const state = { modelCreateDataJsonStr: "", modelSelectDataJsonStr: "", modelClassDataJsonStr: "" }; const getters = { getModelCreateDataJsonStr: state => { return state.modelCreateDataJsonStr; }, getModelSelectDataJsonStr: state => { return state.modelSelectDataJsonStr; }, getModelClassDataJsonStr: state => { return state.modelClassDataJsonStr; } }; const mutations = { SET_MODEL_CREATE_DATA_JSON_STR(state, modelCreateDataJsonStr) { state.modelCreateDataJsonStr = modelCreateDataJsonStr; }, SET_MODEL_SELECT_DATA_JSON_STR(state, modelSelectDataJsonStr) { state.modelSelectDataJsonStr = modelSelectDataJsonStr; }, SET_MODEL_CLASS_DATA_JSON_STR(state, modelClassDataJsonStr) { state.modelClassDataJsonStr = modelClassDataJsonStr; } }; const actions = { setModelCreateDataJsonStr({commit}, modelCreateDataJsonStr) { commit("SET_MODEL_CREATE_DATA_JSON_STR", modelCreateDataJsonStr); }, setModelSelectDataJsonStr({commit}, modelSelectDataJsonStr) { commit("SET_MODEL_SELECT_DATA_JSON_STR", modelSelectDataJsonStr); }, setModelClassDataJsonStr({commit}, modelClassDataJsonStr) { commit("SET_MODEL_CLASS_DATA_JSON_STR", modelClassDataJsonStr); } }; // Exposed warehouse export { state, getters, mutations, actions };
// index.js import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); /** * Batch import all modules under module * If there is a new folder under the module, the JS files in the folder cannot be named with index, which is easy to conflict */ const path = require('path'); const files = require.context('./module', true, /\.js$/); const modules = {}; files.keys().forEach(key => { const name = path.basename(key, '.js'); // Returns the last part of the key modules[name] = files(key).default || files(key); }); Vue.use(Vuex); const store = new Vuex.Store({ modules: modules, }); export default store;