Components are one of the most powerful features of vue.js, and the scope of component instances is independent of each other, which means that data between different components cannot be referenced to each other. Generally speaking, components can have the following relationships:
As shown in the figure above, A and B, B and C, B and D are all parent-child relationships, C and D are sibling relationships, and A and C are intergenerational relationships (may be multiple generations).
Method one, props/$emit
The parent component A is passed to the child component B through props, and B to A is realized by $emit in the B component and v-on in the A component.
1. The parent component passes the value to the child component
Next, we use an example to illustrate how the parent component passes values to the child component: How to get the data in the parent component App.vue in the child component Users.vue users:[“Henry”,”Bucky”,”Emily”]
//App.vue parent component
<template>
<div id=”app”>
<users v-bind:users=”users”></users>//The former has a custom name to facilitate the call of sub-components, and the latter has to pass the data name
</div>
</template>
<script>
import Users from “./components/Users”
export default {
name:’App’,
data(){
return{
users:[“Henry”,”Bucky”,”Emily”]
}
},
components:{
“users”:Users
}
}
//users subcomponent
<template>
<div class=”hello”>
<ul>
<li v-for=”user in users”>{{user}}</li>//Iterate through the passed value, and then present it to the page
</ul>
</div>
</template>
<script>
export default {
name:’HelloWorld’,
props:{
users:{ //This is the custom name of the child label in the parent component
type:Array,
required:true
}
}
}
</script>
Summary: The parent component passes data down to the child component through props. Note: There are three forms of data in the component: data, props, computed
2. The child component passes the value to the parent component (in the form of an event)
Next, we use an example to illustrate how the child component passes the value to the parent component: when we click “Vue.js Demo”, the child component passes the value to the parent component, and the text changes from “What is passed is a value” to ” The child passes the value to the parent component” to realize the pass of the value from the child component to the parent component.
// Subassembly
<template>
<header>
<h1 @click=”changeTitle”>{{title}}</h1>//Bind a click event
</header>
</template>
<script>
export default {
name:’app-header’,
data() {
return {
title:”Vue.js Demo”
}
},
methods:{
changeTitle() {
this.$emit(“titleChanged”,”the child passes the value to the parent component”);//Custom event passes the value “the child passes the value to the parent component”
}
}
}
</script>
// parent component
<template>
<div id=”app”>
<app-header v-on:titleChanged=”updateTitle” ></app-header>//Consistent with the sub-component titleChanged custom event
// updateTitle($event) accepts the passed text
<h2>{{title}}</h2>
</div>
</template>
<script>
import Header from “./components/Header”
export default {
name:’App’,
data(){
return{
title: “Passed is a value”
}
},
methods:{
updateTitle(e){ //Declare this function
this.title = e;
}
},
components:{
“app-header”:Header,
}
}
</script>
Summary: The child component sends messages to the parent component through events, in fact, the child component sends its own data to the parent component.
Method two, $emit/$on
This method uses an empty Vue instance as the central event bus (event center), and uses it to trigger events and monitor events. It cleverly and lightly realizes the communication between any components, including father and child, brothers, and cross-levels. When our project is relatively large, we can choose a better state management solution vuex.
1. Specific implementation method:
var Event=new Vue();
Event.$emit(event name, data);
Event.$on(event name, data => ());
2. Give an example
Suppose there are three sibling components, namely A, B, and C components. How does the C component obtain the data of the A or B component?
<div id=”itany”>
<my-a></my-a>
<my-b></my-b>
<my-c></my-c>
</div>
<template id=”a”>
<div>
<h3>Component A: {{name}}</h3>
<button @click=”send”>Send data to C component</button>
</div>
</template>
<template id=”b”>
<div>
<h3>Component B: {{age}}</h3>
<button @click=”send”>Send the array to the C component</button>
</div>
</template>
<template id=”c”>
<div>
<h3>C component: {{name}}, {{age}}</h3>
</div>
</template>
<script>
var Event = new Vue();//Define an empty Vue instance
var A = {
template:’#a’,
data() {
return {
name:’tom’
}
},
methods: {
send() {
Event.$emit(‘data-a’, this.name);
}
}
}
var B = {
template:’#b’,
data() {
return {
age: 20
}
},
methods: {
send() {
Event.$emit(‘data-b’, this.age);
}
}
}
var C = {
template:’#c’,
data() {
return {
name:”,
age: “”
}
},
mounted() {//Execute after the template is compiled
Event.$on(‘data-a’,name => {
this.name = name;//No new this will be generated inside the arrow function. If you don’t use => here, this refers to Event
})
Event.$on(‘data-b’,age => {
this.age = age;
})
}
}
var vm = new Vue({
el:’#itany’,
components: {
‘my-a’: A,
‘my-b’: B,
‘my-c’: C
}
});
</script>
Method three, vuex
1. Briefly introduce the principle of Vuex
Vuex implements a one-way data flow. It has a State to store data globally. When a component wants to change the data in the State, it must be done through Mutation. Mutation also provides a subscriber mode for external plug-ins to call to obtain State data updates. And when all asynchronous operations (commonly used to call the back-end interface to obtain updated data asynchronously) or batch synchronous operations require Action, but the Action cannot directly modify the State, it still needs to modify the State data through Mutation. Finally, according to the change of State, it is rendered to the view.
2. Briefly introduce the function of each module in the process:
Vue Components: Vue components. On the HTML page, it is responsible for receiving interactive actions such as user operations, and executing the dispatch method to trigger the corresponding action to respond.
Dispatch: Action trigger method, it is the only method that can execute action.
actions: Operational behavior processing module, triggered by $store.dispatch(‘action name’, data1) in the component. Then commit() triggers the call of mutation and indirectly updates the state. Responsible for processing all interactions received by Vue Components. Contains synchronous/asynchronous operations, supports multiple methods with the same name, and triggers them in the order of registration. The operations requested from the background API are performed in this module, including triggering other actions and submitting mutations. This module provides Promise encapsulation to support chain triggering of actions.
commit: The state change commit operation method. Submitting the mutation is the only way to execute the mutation.
Mutations: The state change operation method, which is triggered by commit (‘mutation name’) in actions. It is the only recommended way for Vuex to modify the state. This method can only perform synchronization operations, and the method name can only be globally unique. During the operation, some hooks will be exposed for state monitoring and so on.
state: The page state management container object. Centrally store the scattered data of the data object in Vue components, which is globally unique for unified state management. The data required for page display is read from this object, and Vue’s fine-grained data response mechanism is used to perform efficient status updates.
getters: read method of state object. The module is not listed separately in the figure, it should be included in the render, Vue Components reads the global state object through this method.
3.Vuex and localStorage
Vuex is Vue’s state manager, and the stored data is responsive. But it will not be saved. After refreshing, it will return to the initial state. The specific method should be to save a copy of the data in localStorage when the data in vuex changes. After refreshing, if there is saved data in localStorage, take it out and replace it. State in the store.
let defaultCity = “Shanghai”
try {// The user has turned off the local storage function, and now add a try…catch to the outer layer
if (!defaultCity){
defaultCity = JSON.parse(window.localStorage.getItem(‘defaultCity’))
}
}catch(e){}
export default new Vuex.Store({
state: {
city: defaultCity
},
mutations: {
changeCity(state, city) {
state.city = city
try {
window.localStorage.setItem(‘defaultCity’, JSON.stringify(state.city));
// When the data changes, save a copy of the data to localStorage
} catch (e) {}
}
}
})
What needs to be noted here is: because in vuex, the states we save are all arrays, and localStorage only supports strings, so we need to use JSON conversion:
JSON.stringify(state.subscribeList); // array -> string
JSON.parse(window.localStorage.getItem(“subscribeList”)); // string -> array
Method 4: $attrs/$listeners
1 Introduction
When multi-level component nesting needs to pass data, the usual method is through vuex. But if you just pass data without intermediate processing and use vuex to process it, it would be a bit of an overkill. For this Vue2.4 version provides another method-$attrs/$listeners
$attrs: Contains the attribute bindings (except class and style) that are not recognized (and obtained) by props in the parent scope. When a component does not declare any props, it will include all parent scope bindings (except class and style), and internal components can be passed in via v-bind=”$attrs”. Usually used with the interitAttrs option.
$listeners: Contains the v-on event listeners in the parent scope (without the .native decorator). It can pass in internal components via v-on=”$listeners”
Next we look at an example of cross-level communication:
// index.vue
<template>
<div>
<child-com1
:foo=”foo”
:boo=”boo”
:coo=”coo”
:doo=”doo”
title=”Front end craftsman”
></child-com1>
</div>
</template>
<script>
const childCom1 = () => import(“./childCom1.vue”);
export default {
components: {childCom1 },
data() {
return {
foo: “Javascript”,
boo: “Html”,
coo: “CSS”,
doo: “Vue”
};
}
};
</script>
// childCom1.vue
<template class=”border”>
<div>
<p>foo: {{ foo }}</p>
<p>$attrs of 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 that are automatically mounted to the root element of the component that are not declared in props
props: {
foo: String // foo is bound as props
},
created() {
console.log(this.$attrs); // {“boo”: “Html”, “coo”: “CSS”, “doo”: “Vue”, “title”: “Front-end craftsman”}
}
};
</script>
// childCom2.vue
<template>
<div class=”border”>
<p>boo: {{ boo }}</p>
<p>childCom2: {{ $attrs }}</p>
<child-com3 v-bind=”$attrs”></child-com3>
</div>
</template>
<script>
const childCom3 = () => import(“./childCom3.vue”);
export default {
components: {
childCom3
},
inheritAttrs: false,
props: {
boo: String
},
created() {
console.log(this.$attrs); // {“coo”: “CSS”, “doo”: “Vue”, “title”: “Front-end craftsman”}
}
};
</script>
// childCom3.vue
<template>
<div class=”border”>
<p>childCom3: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
props: {
coo: String,
title: String
}
};
</script>
As shown in the figure above, $attrs represents objects that have no inherited data, and the format is {attribute name: attribute value}. Vue2.4 provides $attrs and $listeners to pass data and events, and the communication between cross-level components becomes simpler.
Simply put: $attrs and $listeners are two objects. $attrs stores the non-Props properties bound in the parent component, and $listeners stores the non-native events bound in the parent component.
ps: inheritAttrs
The final rendered result: Elements
The default value is true
false
Summarize:
As can be seen from the above example, the premise: the properties passed by the parent component are not registered in the props of the child component.
1. When inheritAttrs: true (default) is set, the top-level tag element of the child component (div element in this example) will render the attributes passed by the parent component (aaa=”1111″ in this example).
2. When inheritAttrs: false is set, the top-level tag element of the child component (div element in this example) will not render the attributes passed by the parent component (aaa=”1111″ in this example).
3. Regardless of whether inheritAttrs is true or false, the child component can get the attributes passed from the parent component through the $attrs attribute.
Method five, provide/inject
1 Introduction
Vue 2.2.0 adds API. This pair of options needs to be used together to allow an ancestor component to inject a dependency into all its descendants, no matter how deep the component level is, and it will always take effect when the upstream and downstream relationship is established. In a nutshell: ancestor components provide variables through providers, and then inject variables in descendant components.
The provide / inject API mainly solves the communication problem between cross-level components, but its usage scenario is mainly that the sub-components obtain the status of the upper-level components, and a relationship between active provision and dependency injection is established between cross-level components.
2. Give an example
Suppose there are two components: A.vue and B.vue, B is a child component of A
// A.vue
export default {
provide: {
name:’hello’
}
}
// B.vue
export default {
inject: [‘name’],
mounted () {
console.log(this.name); // hello
}
}
As you can see, in A.vue, we have set a provide: name with a value of a boat in the waves, and its function is to provide the variable name to all its subcomponents. In B.vue, the name variable provided from component A is injected through inject, then in component B, this variable can be accessed directly through this.name, and its value is also in the waves. This is the core usage of provide / inject API.
Need to pay attention to: provide and inject