By default, data cannot be shared between components, but data can be passed between components in the following ways:

props

Data transfer between parent and child components:

  • The father the son
  • Child the parent

The father the son

  • Make sure there is data in the parent
  • Bind data to child components using property binding in the parent component’s template
  • Define the props property in the child component to receive data passed by the parent
  • The received data can be used directly in the template of the child component

The parent binds the data and the child receives the data

Detailed format:

Props:{Data item name :{type: type. Specifies what type of data must be passed from the parent component. Its value is: Object, Array, a String, Number, Boolean is the constructor. Do not write it as a string default:// The default value. When the parent component is not transferring data, the value required is used:true/false. Does it have to be passed in}}Copy the code

Child the parent

  • In the parent component’s template, add an event listener to the child component
  • In a child component, a certain time passesthis.$emitEmit this event and emit data (this.$emit(” event name “, additional data))
  • When a method in the parent fires, data is applied to the method’s first argument

Father to son to grandson, only one level, not across levels

Example:

<body> <! - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- > <! -- Father to son --> <! -- <div id="app"> < H1 > Parent component -> Data: {{num}}</h1> <hr> <son :sonnum="num" :sonname="name"></son>
    </div>

    <template id="son"> < div > child components - > data: {{mysum}} - > {{sonname}} < button @ click ="sonnum=200"> modify the data of 200 < / button > < h2 > {{mysum}} < / h2 > < button @ click ="mysum=200"</button> </div> </template> --> <! - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- > <! --> <div id="app"> <h1> Parent component </h1> < son@submitmsg ="addmsg"></son>
        <h2>{{a}}</h2>
    </div>

    <template id="son"> <div> <h3> child component </h3> < button@click ="fashe"Launch > < / button > < / div > < / template > < script > / father/child and * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *let Son = {
            template: "#son".data() {
                return {
                    num:111,
                }
            },
            methods: {
                fashe() {
                    this.$emit("submitmsg", this.num)
                }
            }
        }
        let vm = new Vue({
            el: "#app", data: { a: 0, }, methods: { addmsg(info) { this.a = info } }, components: {Son,}}) / / father the Son * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * / /let Son = {
        //     template: "#son", / /data() {
        //         return {
        //             mysum: this.sonnum,

        //         }
        //     },
        //     props: {
        //         sonnum: Number,
        //         sonname: {
        //             type: String,
        //             // required:true,
        //             default: "jun",
        //         }
        //     },
        //     methods: {

        //     }
        // }
        // let vm = new Vue({
        //     el: "#app",
        //     data: {
        //         num: 100,
        //         name: "fan"
        //     },
        //     methods: {

        //     },
        //     components: {
        //         Son,
        //     }
        // })
//********************************************************************************
    </script>
</body>
Copy the code

So many things, I believe you are too lazy to see, you can build a file, copy to the inside test

$attrs

If you want to pass data from a parent component to a child component, using the props binding to pass information is obviously cumbersome. To address this requirement, $attrs was introduced

$attrs collects all attributes passed in the parent component except those not defined by props in the component.

Example: Start with three components A-B-C and pass properties from A to C. Basically, layer by layer, pass down through props

<template>
  <div id="app">
    A{{msg}}
    <component-b :msg="msg"></component-b>
  </div>
</template>
<script>
let vm = new Vue({
  el: "#app",
  data: {
    msg: "100"
  },
  components: {
    ComponentB: {
      props: ["msg"],
      template: `<div>B<component-c :msg="msg"></component-c></div>`,
      components: {
        ComponentC: {
          props: ["msg"],
          template: "<div>C{{msg}}</div>"}}}}}); </script>Copy the code

$attrs = $attrs = $attrs = $attrs = $attrs = $attrs = $attrs = $attrs = $attrs = $attrs = $attrs

<script>
let vm = new Vue({
  el: "#app",
  data: {
    msg: "100"
  },
  components: {
    ComponentB: {
      inheritAttrs: false,
      template: `<div>B<component-c v-bind="$attrs"></component-c></div>`,
      components: {
        ComponentC: {
          props: ["msg"],
          template: "<div>C{{msg}}</div>"}}}}}); </script>Copy the code

In this way, data transfer can be very convenient, and it is also relatively simple to use, avoiding the pain of writing props

Generally in use$attrs, will be addedinheritAttrs:falseWhat it does is it doesn’t show up in the DOM structure when it’s not used

$listeners

$attrs = $attrs; $attrs = $attrs; $attrs = $attrs; $attrs = $attrs $listeners are used here

If the root element of the component doesn’t have any DOM events, but the elements inside the root element do, you can use $Listeners to get all the event functions passed in by the parent component and bind them to the internal elements by v-on=” XXX “. In short, all methods passed by the parent component to the child component are stored in $Listeners

The.native modifier is sometimes used to bind native events to components, but the downside is that the binding is invalid if the root element of the component does not use the event, and it is not easy to control its event scope, so we generally do not use this modifier

Example:

<template> <div> ParentPage < button@click ="handleClick">ParentClick</button>
    <Child @customClick="handleClick" />
  </div>
</template>

<script>
import Child from "./Child";
export default {
  name: "ParentPage",

  components: {
    Child
  },

  methods: {
    handleClick() {
      alert("hello"); }}}; </script>Copy the code
// Child <template> <div> ChildPage <! -- <button @click="$emit('customClick')">ChildClick</button> -->
    <button @click="$listeners.customClick">ChildClick</button>
  </div>
</template>

<script>
import SubChild from "./SubChild.vue";
export default {
  name: "ChildPage",
  components: {
    SubChild
  },
  data() {
    return{}; }}; </script>Copy the code

Child listeners pass the parent method V-on =”$listeners” to child listeners when multiple layers of components reference them

// Child <template> <div> ChildPage <! -- <button @click="$emit('customClick')">ChildClick</button> -->
    <button @click="$listeners.customClick">ChildClick</button>
    <SubChild v-on="$listeners" />
  </div>
</template>

<script>
import SubChild from "./SubChild.vue";
export default {
  name: "ChildPage",
  components: {
    SubChild
  },
  data() {
    return{}; }}; </script>Copy the code
<template> <div> SubChildPage < button@click ="$listeners.customClick">SubChildClick</button>
  </div>
</template>

<script>
export default {
  name: "SubChildPage".data() {
    return{}; }}; </script>Copy the code

If you take a good look at the above code, you will understand

$emit

The parent component can use props to pass data to the child component. The child component can use $emit to trigger custom events for the parent component

vm.$emit(event, arG) // Triggers the event VM on the current instance.$on( event, fn ); // Run fn after listening for event events;Copy the code

Example:

<template> <div> <div>$emitThe child component calls the parent component's methods and passes data </div> < H1 > Parent component data: {{MSG}}</h1> < ema-ch@updateinfo ="updateInfo" :sendData="msg"></emit-ch>
  </div>
</template>
<script>
import emitCh from ". /$emitCh";
export default {
  name: "emitFa",
  components: { emitCh },
  data() {
    return {
      msg: "Beijing"}; }, methods: {updateInfo(data) {console.log(data) is triggered when a child component button is clicked; this.msg = data.city; // Change the value of parent component}}}; </script>Copy the code
<template>
  <div class="train-city"< <h3> Data from parent to child: {{sendData}}</h3> <br /> < button@click ="select()"</button> </div> </template> <script>export default {
  name: "emitCh"// this is the same as a global ID. Props: ["sendData"], // To receive data from the parent to the childdata() {
    return {};
  },
  computed: {},
  methods: {
    select() {
      let data = {
        city: "Hangzhou"
      };
      this.$emit("updateInfo", data); // If the select event is triggered, the updateInfo event is automatically triggered. </script>Copy the code

This.$emit this is the parent component of this.$emit this is the parent component

$refs

$refsYou can use it by adding it to an element or component tagrefProperty specifies a reference that will be registered in the parent component’s$refsObject, used in JS$refsTo point to a DOM element or component instance;

  • First mark your child: < firstChild ref=”test”>

  • In the parent component, this.$refs.test allows you to access the child component, including the data in the child component, and call its functions

$parentwith$children

$parent $children $refs $parent $refs

  • usethis.$parentYou can look for the parent of the current component.
  • usethis.$childrenYou can look for direct children of the current component, and you can walk through all children$childrenIt’s not sequential, it’s not reactive.

Of course, you can also use this.$root to find the root component and use $children to traverse all components.

Note: both of these are unbounded, meaning that you can directly find the outermost data or the innermost data, of course, if you know the order of the child components, you can also use subscripts to operate

Example:

// Parent <template> <div class="game">
    <h2>{{ msg }}</h2>
    <LOL ref="lol"></LOL>
    <DNF ref="dnf"></DNF>
  </div>
</template>
<script>
import LOL from "@/components/game/LOL";
import DNF from "@/components/game/DNF";
export default {
  name: "game",
  components: {
    LOL,
    DNF
  },
  data() {
    return {
      msg: "Game",
      lolMsg: "Game->LOL",
      dnfMsg: "Game->DNF"
    };
  },
  methods: {},
  mounted() {// mounted //$childrenSorting of child components is not safe in console.log(this.$children[0].gameMsg); //LOL->Game // read named subcomponent data console.log(this.$refs.dnf.gameMsg); //DNF->Game // Find component data console.log(this) from the root component.$root.$children[0].msg); //APP
    console.log(this.$root.$children[0].$children[0].msg); //Game
    console.log(this.$root.$children[0].$children[0].$children[0].msg); //Game->LOL
    console.log(this.$root.$children[0].$children[0].$children[1].msg); //Game->DNF
  }
};
</script>
Copy the code
// subcomponent LOL <template> <div class="lol">
    <h2>{{ msg }}</h2>
  </div>
</template>

<script>
export default {
  name: "LOL".data() {
    return {
      msg: "LOL",
      gameMsg: "LOL->Game"
    };
  },
  methods: {},
  created() {this. MSG = this.$parent.lolMsg; }}; </script>Copy the code
// DNF <template> <div class="dnf">
    <h2>{{ msg }}</h2>
  </div>
</template>

<script>
import Bus from ".. /.. /utils/bus.js";
export default {
  name: "DNF".data() {
    return {
      msg: "DNF",
      gameMsg: "DNF->Game"
    };
  },
  methods: {},
  created() {// Look down from the root component to find the parent component data this. MSG = this.$root.$children[0].$children[0].dnfMsg;
    //this.msg = this.$children.dnfMsg; }}; </script>Copy the code

$parent gets all the child components from the parent component. $children gets all the child components from the parent component

providewithinject

The scenarios of provide and Inject are also used for component value transmission, especially grandfather components, such as children and children components, and one-way value transmission (from components provided to components of Inject). Not recommended

  • The provide option should be an object or a function that returns an object. This object contains properties that can be injected into its descendants.
  • Inject is usually an array of strings.

Example:

// The parent component <template> <div> <father-dom> </father-dom> </div> </template> <script> import sonDom from"./sonDom.vue";
export default {
  provide: {
    fooNew: "bar"
  },
  data() {
    return {};
  },
  components: { sonDom },
  methods: {}
};
</script>
Copy the code
// Child <template> <div> <child-dom></child-dom> </div> </template> <script> import childDom from"./childDom.vue";
export default {
  name: "son-dom",
  components: { childDom }
};
</script>
Copy the code
/ / child child components < template > < div > < p > fooNew: {{fooNew}} < / p > < / div > < / template > < script >export default {
  name: "childDom",
  inject: ["fooNew"],
  methods: {}
};
</script>
Copy the code

Vuex

Let’s move on to our finale, the sixth data transfer method: Vuex

The simplicity of one-way data flow can easily be compromised when our application encounters state shared by multiple components.

  • Multiple views depend on the same state.
  • Actions from different views need to change the same state.

For problem one, the method of passing parameters can be cumbersome for multi-layer nested components and does nothing to transfer state between sibling components. For problem two, we often use parent-child components to reference directly or to change and synchronize multiple copies of state through events. These patterns are very fragile and often result in unmaintainable code.

So why don’t we extract the shared state of the components and manage it in a global singleton? In this mode, our tree of components forms a giant “view” where any component can get state or trigger behavior no matter where it is in the tree!

In addition, by defining and isolating concepts in state management and enforcing compliance with certain rules, our code becomes more structured and maintainable.

Vuex

  • State State in the Vuex is a global state that you can retrieve and modify anywhere in the Component. Using Vuex does not mean that you need to put all the states into Vuex. While putting all the state in Vuex makes state changes more explicit and easier to debug, it also makes the code tedious and unintuitive. If there are states that belong strictly to a single component, it is best to treat them as local states of the component. You should make trade-offs and decisions based on your application development needs.
// Get state this.$store.state.count

//vuex的辅助方法
import { mapState } from 'vuex'The computed: mapState (['count'
])
Copy the code
  • Getters in getters Vuex is similar to computed, and sometimes we need to derive some state from state in the store, such as filtering and counting lists. If we have multiple components that need this property, we can either copy this function, Or extract a shared function and import it in multiple places — neither is ideal. Vuex allows us to define “getters” (you can think of them as computed properties of the store) in the store. Just like evaluating properties, the return value of a getter is cached based on its dependency and is recalculated only if its dependency value changes.
// Use this directly.$store.getters. DoneTodosCount // Use the helper method import {mapGetters} from'vuex'The computed: mapGetters ({doneCount: 'doneTodosCount'
})
Copy the code
  • Mutations the only way to change the state in Vuex’s store is to submit mutation. Substituting constants for mutation event types is a common pattern in various Flux implementations. This allows tools like Linter to work, and keeping these constants in a separate file allows your code collaborators to see mutations throughout your app. Whether or not you use constants is up to you — this can be very helpful on large projects that require multiple people to work together. But if you don’t like it, you don’t have to. An important rule to remember is that mutation must be a synchronous function, a callback from an asynchronous function of mutation. When mutation was triggered, the callback function had not yet been called. Devtools doesn’t know when a callback is actually called — essentially any state changes made in a callback are untraceable. (Usually request and timer methods are asynchronous functions)
// trigger mutations this.$store.commit('xxx') // Import {mapMutations} from'vuex'Methods: mapMutations (['increment' ])
Copy the code
  • The official interpretation of actions for actions is as follows. Similar to mutation, except that:
  • The Action commits mutation rather than a direct state change.
  • Actions can contain any asynchronous operation.

Use actions if you have asynchronous complex logic that can be called repeatedly.

// Trigger action store.dispatch('increment'// Helper function import {mapActions} from'vuex'Methods: mapActions (['increment' ])
Copy the code
  • Module Because it uses a single state tree, all the application states are grouped into one large object. When the application becomes very complex, the Store object can become quite bloated.

To solve these problems, Vuex allows us to split the Store into modules. Each module has its own state, mutation, action, getter, and even nested submodules — split the same way from top to bottom.

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
Copy the code

After reading this article, you will have a better understanding of data transfer and communication between components


^ _ <