This is the 19th day of my participation in the Genwen Challenge

Component is one of the powerful functions of VUE, and the scope of each component is independent, that is, the data of each component is relatively independent, so the communication between components has become the core problem to be solved, usually components have the following situations:

As shown in the figure above, A and B, B and C, B and D are all father-child relationships, C and D are brothers, A and C, A and D are atavistic relationships (possibly multiple generations apart).

Method one:props / $emit

This method is used for parent-child component communication. Parent component A uses props to transmit values to child component B, and child component B uses $emit to transmit values to parent component A. Component A uses V-ON to receive values from component B. Here’s an example:

1 Parent component passes value to child component:

Parent component code:

<template>
    <div class="list">
        <item :goods="goods"></item>
    </div>
</template>
<script>
import Item from "./components/Item"
export default {
  name: 'App'.data(){
    return{
      goods: {
        name: 'iPhone XS Max'.price: 10000}}},components: {"item":item
  }
}
</script>
Copy the code

Sub-component code:

<template>
 <div>{{goods. Name}} {{goods. Price}}</div>
</template>
<script>
export default {
  props: {
    goods: {
      type: Object.default: null}}}</script>
Copy the code

The parent component passes data down to the child component via props. Note: There are three forms of data in the component: Data, props, and computed.

2 Child components transmit values to parent components

Child components

<template>
  <div>{{goods. Name}} {{goods. Price}}<el-button @click='changePrice'>Click on the</el-button>
  </div>
</template>
<script>
export default {
  props: {
    goods: {
      type: Object.default: null}},methods: {
    changePrice () {
      // Issue the change event for the parent to listen to and pass the value "child to parent value"
      this.$emit('change'.'Value passed from child to parent')}}}</script>
Copy the code

The parent component

<template>
  <div class="hello">
    <item
      :goods="goods"
      @change='changePrice'
    ></item>
  </div>
</template>

<script>
import Item from '@/components/Item'
export default {
  data () {
    return {
      goods: {
        name: 'iPhone XS Max'.price: 10000}}},methods: {
    // Listen for the change event using v-on (abbreviated @) with the value passed by the child component
    changePrice (val) {
      console.log(val)
      this.goods.price = val
    }
  },
  components: { Item }
}
</script>
Copy the code

Method two: the central event buseventBus $emit / $on

This approach uses an empty Vue instance as the central event bus (event hub) to trigger and listen for events, subtly and lightly enabling communication between any component, including parent, sibling, and cross-level.

1 Specific implementation mode

var Event=new Vue();  // Define a new Vue instance$emit(Event name, data);// Use $emit to pass$on(Event name,data= > {});  // Use $on to receive
Copy the code

2 Example Description

A, B, and C are siblings. A and B pass data to C, and C receives data from A and B.

A.vue

<template>
  <div>
    <el-button @click='giveDataToC'>A passes A value to C</el-button>
  </div>
</template>
<script>
import Vue from 'vue'
window.Event = new Vue()
export default {
  methods: {
    giveDataToC () {
      window.Event.$emit('data-A'.'data from A')}}}</script>
Copy the code

B.vue

<template>
  <div>
    <el-button @click='giveDataToC'>B passes a value to C</el-button>
  </div>
</template>
<script>
export default {
  methods: {
    giveDataToC () {
      window.Event.$emit('data-B'.'data from A')}}}</script>
Copy the code

C.vue

$on listens for custom events data-a and data-b. In mounted or created hooks, it is not always clear when an event will be raised.

<template>
  <div>
    <div>Data from A: {{A}}</div>
    <div>Data from B: {{B}}</div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      A: ' '.B: ' '
    }
  },
  mounted () {
    window.Event.$on('data-A'.val= > {
      this.A = val
    })
    window.Event.$on('data-B'.val= > {
      console.log('form')
      this.B = val
    })
  }
}
</script>
<style scoped>
div {
  margin-bottom: 20px;
}
</style>
Copy the code

Note: Use the same Event

Methods three$attrs / $listeners

Vue 2.4 provides multi-component nested values without data processing in the middle.

1 explain

$attrs: contains feature bindings (except class and style) that are not recognized (and retrieved) as prop in the parent scope. When a component does not declare any prop, all parent-scoped bindings (except class and style) are included, and internal components can be passed in via V-bind =”$attrs” — useful when creating higher-level components.

$Listeners: Contains V-on event listeners in the parent scope (without.native modifiers). Internal components can be passed in via V-on =”$Listeners “– useful for creating higher-level components.

Example 2

parent.vue

<template>
  <div>
    <strong>This is the parent component</strong>
    <child-a
      :content=content
      :shape=shape
      :act=act
      :lib=lib
      title="Front-end requirements"
      @event1="ev1"
      @event2="ev2"
    ></child-a>
  </div>
</template>
<script>
import ChildA from '@/components/children/childA'
export default {
  components: { ChildA },
  data () {
    return {
      content: 'html'.shape: 'css'.act: 'Javascript'.lib: 'Vue'}},methods: {
    ev1 () {
      console.log('ev1')
    },
    ev2 () {
      console.log('ev2')}}}</script>
<style scoped>
div{
  color: red;
  margin: 30px;
}
</style>
Copy the code

childA.vue

<template>
  <div>
    <p>This is component A</p>
    <p>content: {{ content }}</p>
    <p>ChildA $attrs: {{$attrs}}</p>
    <child-b
      v-bind="$attrs"
      v-on="$listeners"
    ></child-b>
  </div>
</template>
<script>
import ChildB from '@/components/children/ChildB'
export default {
  props: {
    content: String
  },
  components: { ChildB },
  inheritAttrs: false.// You can turn off properties that are not declared in props that are automatically mounted to component root elements
  created () {
    console.log(this.$attrs);
  },
  mounted () {
    this.$emit('event1')
    console.log(this.$listeners)
  }
}
</script>
<style scoped>
div{
  padding-top: 30px;
  color: green;
}
p{
  line-height: 2
}
</style>
Copy the code

childB.vue

<template>
  <div>
    <p>This is component B</p>
    <p>shape: {{ shape }}</p>
    <p>ChildB $attrs: {{$attrs}}</p>
    <child-c
      v-bind="$attrs"
      v-on="$listeners"
    ></child-c>
  </div>
</template>
<script>
import ChildC from '@/components/children/ChildC'
export default {
  props: {
    shape: String
  },
  components: { ChildC },
  inheritAttrs: false.// You can turn off properties that are not declared in props that are automatically mounted to component root elements
  created () {
    console.log(this.$attrs); }}</script>
<style scoped>
  div{
    padding-top: 30px; 
  }
  p{
    line-height: 2;
  }
</style>
Copy the code

childC.vue

<template>
  <div>
    <p>This is component C:</p>
    <p>ChildC $attrs: {{$attrs}}</p>
    <p>Lib: {{lib}}</p>
    <p>Title: {{title}}</p>
    <el-button @click="event1">ev1</el-button>
  </div>
</template>
<script>
export default {
  props: {
    lib: String.title: String
  },
  inheritAttrs: false.// You can turn off properties that are not declared in props that are automatically mounted to component root elements
  created () {
    console.log(this.$attrs);
  },
  mounted () {

  },
  methods: {
    event1 () {
      this.$listeners.event1()
    }
  }
}
</script>
<style scoped>
div{
  padding-top: 30px;
  color: yellowgreen;
}
p{
  line-height: 2;
}
</style>
Copy the code

To define data and events in the parent component, $attrs in children, grandchildren, and more descendants can inherit properties in addition to the component’s props. Children, grandchildren, and more descendants can use this.$listener. Event name to execute the event in the parent component.

Methods fourprovide / inject

These two methods are new to VUE 2.2.0.

1 explain

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.

The Inject option should be:

  • An array of strings, or
  • An object whose key is the local binding name and value is:
    • Search for the key (string or Symbol) used in the available injection content, or
    • An object of which:
      • The FROM attribute is the key (string or Symbol) to search for in the available injection content
      • The default attribute is the value used in the case of degradation

The ancestor component provides variables through provider, and the descendant component injects variables through Inject. Provide/Inject API mainly solves the communication problem between cross-level components, but its usage scenario is mainly that sub-components obtain the state of the upper level components, and a relationship between active provision and dependency injection is established between cross-level components. Provide and Inject binding are not responsive. This is intentional. However, if you pass in a listening object, the object’s properties are still responsive.

Example 2

The parent component. Vue

<template>
  <div>
    <child-a></child-a>
    <el-button @click='change'>change</el-button>
  </div>
</template>
<script>
import ChildA from '@/components/provide/ChildA'
export default {
  provide: {
    name: 'This is a data provide'
  },
  components: { ChildA },
  methods: {
    change () {
      this.name = 'Let's change it and see if the child component stays the same.'}}}</script>
<style scoped>
div{
  margin: 50px;
}
</style>
Copy the code

Subcomponents. Vue

<template>
  <div>Content from parent component: {{name}}</div>
</template>
<script>
export default {
  inject: ['name']}</script>
Copy the code

As you can see, define provide in the parent component and use Inject in the child component to get the value of provide in the parent component. However, if we click modify the value of the parent component, the value of the child component will not change.

3 provide/injectImplementing responsiveness

Provide instance of the ancestor component, so that you can modify the properties of the instance of the ancestor component directly in the descendant component. The disadvantage of this method is that there are a lot of unnecessary functions mounted on the instance, such as props, Provide responsive optimization using the latest 2.6 API vue.Observable

Method 1 Example:

The parent component

<template>
  <div>
    <p>The parent component<el-button @click="change('red')">Change the Color</el-button>
    </p>

    <child-a></child-a>
  </div>
</template>
<script>
import ChildA from "@/components/provide/ChildA";
export default {
  data() {
    return {
      color: "blue"
    };
  },
  provide() {
    return {
      theme: this // Method one: provide an instance of the ancestor component
    };
  },
  components: { ChildA },
  methods: {
    change(color) {
      if (color) {
        this.color = color;
      } else {
        this.color = this.color === "blue" ? "red" : "blue"; }}}};</script>
<style scoped>
div {
  margin: 50px;
}
</style>
Copy the code

Child components

<template>
  <div :style="{ color: theme.color }">Child component A comes from the content of the parent component</div>
</template>
<script>
export default {
  inject: {
    theme: {
      // Functional components have different values
      default: () = >({})}}};</script>
Copy the code

Method 2 example:

The parent component

<template>
  <div>
    <p>The parent component<el-button @click="change('red')">Change the Color</el-button>
    </p>

    <child-a></child-a>
  </div>
</template>
<script>
import ChildA from "@/components/provide/ChildA";
import Vue from "vue";
export default {
  data() {
    return {
      color: "blue"
    };
  },
  provide() {
    this.theme = Vue.observable({
      color: "blue"
    });
    return {
      theme: this.theme
    };
  },
  components: { ChildA },
  methods: {
    change(color) {
      if (color) {
        this.theme.color = color;
      } else {
        this.theme.color = this.theme.color === "blue" ? "red" : "blue"; }}}};</script>
<style scoped>
div {
  margin: 50px;
}
</style>
Copy the code

Child components

<template>
  <div :style="{ color: theme.color }">Child component A comes from the content of the parent component</div>
</template>
<script>
export default {
  inject: {
    theme: {
      // Functional components have different values
      default: () = >({})}}};</script>
Copy the code

Methods five$parent / $childrenref

  • refIf used on a normal DOM element, the reference refers to the DOM element. If used on a child component, the reference refers to the component instance
  • $parent / $children: Accesses the parent/child instance

The parent component. Vue

<template>
  <div>
    {{dataA}}
    <child-a ref="childA"></child-a>
  </div>
</template>
<script>
import ChildA from "@/components/ref/ChildA";
export default {
  data() {
    return {
      dataA: "".dataParent: "This is the data from the parent component."
    };
  },
  components: { ChildA },
  mounted() {
    const childA = this.$refs.childA;
    console.log(childA.name1);
    this.dataA = childA.name1;
    console.log(this.$children[0].name2); childA.operationA(); }};</script>
Copy the code

Subcomponents. Vue

<template>
  <div>{{dataFrom}}</div>
</template>
<script>
export default {
  data() {
    return {
      name1: "Here's the data from child component A.".name2: "This is also data from child component A.".dataFrom: ""
    };
  },
  mounted() {
    this.dataFrom = this.$parent.dataParent;
  },
  methods: {
    operationA() {
      console.log("This is an operation from a child component."); }}};</script>
Copy the code

Both get the component instance directly, and then you can call the component’s methods or access the data directly. It cannot communicate between siblings or cross-level components. You can use $parent directly to get the parent component and access its data and methods. You can access the child’s data and methods by getting the child component (which is an array of child components) with $children.

Methods six$boradcast / $dispatch

This also came in pairs, but it was only provided in Vue1.0, and Vue2.0 was deprecated.

Methods sevenVuex

  • Vue Components:VueComponents.HTMLPage, responsible for receiving user operations and other interactive behavior, executedispatchMethod trigger correspondenceactionRespond.
  • dispatch: action action trigger method, is the only method that can execute action.
  • actions: Action behavior processing module, composed of components$store.dispatch(' Action name ', data1)To trigger. And then bycommit()To triggermutationTo update indirectlystate. Responsible for handling all interactions received by Vue Components. Contains synchronous/asynchronous operations and supports multiple methods of the same name that are triggered in the order of registration. Requests to the background API are made in this module, including triggering othersactionAnd submitmutationIn the operation. This module providesPromisePackage to supportactionThe chain trigger.
  • commit: State change submission operation method. rightmutationCommit is the only thing that can be donemutationMethods.
  • mutations: State change operation method, byactionsIn theCommit (' mutation name)To trigger. isVuexModify thestateIs the only recommended method. This method can only perform synchronous operations, and the method name must be globally unique. There’s going to be somehookExpose to carrystateMonitoring, etc.
  • state: page state management container object. Store Vue Components centrallydataObject’s fragmented data, globally unique, for unified state management. The data required for page display is read from this object, leveraging Vue’s fine-grained data response mechanism for efficient status updates.
  • getters:stateObject reading method. This module is not listed separately in the figure and should be includedrenderVue Components reads globally through this methodstateObject.

One last word

If this article is helpful to you, or inspired, help pay attention to it, your support is the biggest motivation I insist on writing, thank you for your support.