Component communication between parents and grandchildren of vue and component communication between brothers

Keywords: Javascript Front-end Vue.js

Component communication between parent and child components

  • Interview question: what are the communication modes between vue components?

The first: props+this.$emit:

props:

Parent component A binds data through v-bind and transfers data to child components, which are received by props

Parent component A:

<template>
  <div class="parent-root">
    <child class="child"  :message="message"> </child>
  </div>
</template>

<script>
import child from "@/components/child";
export default {
  name: "parent",
  components: { child },
  data() {
    return {
      message:"Ba Ba's data"
    };
  },
     </script>

Sub assembly B:

<template>
  <div class="child-root">
    Message from parent component:{{message}}   
  </div>
</template>

<script>
  export default {
    name: 'child',
    props: ['message'],
 </script>

this.$emit:

The parent component can directly use v-on to listen to the events triggered by the child component where the child component is used, bind the user-defined event eventName with v-on, and then use $emit(eventName,data) in the child component to trigger the event

Parent component A:


Sub assembly B:

The second: style, class, and custom attributes

The parent component can add style, class and custom attributes to the child component label, and the child component will be merged into its own root label

Parent component A:

<template>
  <div class="parent-root">
     <child class="child" style="color:#ccc" datd-a="5" :message="message"> </child>
  </div>
</template>

<script>
import child from "@/components/child";
export default {
  name: "parent",
  components: { child },
  data() {
    return {
      message:"Ba Ba's data"
    };
  },
     </script>

Sub assembly B:

<template>
  <div class="child-root">
    Message from parent component:{{message}}   
  </div>
</template>

<script>
  export default {
    name: 'child',
    props: ['message'],
 </script>

The third: this.$attrs, this.$listeners, and inheritAttrs

  • this.$attrs between parent and child components stores other attributes passed by negative components except style, class, custom attributes and attributes received by props. It is usually used together with the interitAttrs option
  • It should be noted that after the child component uses props to receive the attribute data from the parent component, the attribute will not be stored in this.$attrs
  • this.$attrs can be used to transfer data between parents and grandchildren, so there is no need to use v-bind and props to transfer data layer by layer in the child components of each layer
  • this.$listeners stores all the events bound by the parent component with v-on (excluding the. native modifier). The child component can pass all the events to the subsequent child components through v-bind:$listeners
  • inheritAttrs: the default value is true, and the attribute value will be automatically on the mounted component element. If props declares an attribute, the undeclared attribute will be mounted; false turns off the attribute automatically mounted on the component root element. Note: this option does not affect class and style bindings.

Parent component:

<template>
  <div class="parent-root">
    <child class="child" :name="name" :age="age" :data="data" @change="change" @childEvent="childEvent"> </child>
    <p>Value passed by the sub component:{{text}}</p>
  </div>
</template>

<script>
  import child from "@/components/child";
  export default {
    name: 'parent',
    components: {child},
    data() {
      return {
        name:"Xiao Ming",
        age:18,
        text:'',
        data:"me"
      };
    },
    methods: {
      //Events passed by the sun component
      change(text) {
        this.text = text;
      },
      childEvent(name){
console.log("name:",name);
      }
    },
  };
</script>

Subcomponents:

Sub assembly:

  • inheritAttrs:

    • When inheritAttrs is true:
    • When inheritAttrs is false:

The fourth: this.$parent and this.$children

Within the component, you can get the parent component and child component instances of the current component through the $parent and $children attributes
result:

Fifth: Provide and Inject

Parent component instances can use Provide to pass data to descendant components, and descendant components use inject to receive data,

However, it should be noted that the data passed using this method is not responsive. However, if you pass in a listener object, the object's property is still responsive.

For details: https://cn.vuejs.org/v2/api/?#provide-inject

Parent component:

Subcomponents:

The sixth: v-model

v-model is specially used for form elements when bound to form elements

  • When the form is an input form, v-model will finally generate a value attribute and input event
  • When a multi-choice or radio box is bound, v-model finally generates a checked attribute and change event

The essence of v-model instruction is a syntax sugar, which is a combination of value attribute and input event

<input :value="data" @input="data=$event.target.value" />
<!-- Equivalent to -->
<input v-model="data" />

See: Form input binding

$event.target.value
 Gets the of the trigger event target,Is what triggers the event DOM Elemental value

**When v-model is bound to a component (equivalent to prop+this.$emit)**

  • When the parent component passes a value to the child component through v-model, it will automatically pass a prop attribute of value. In the child component, the value bound by v-model will be automatically modified through this.$emit('input ', val)
<!-- Parent component -->
<template> 
    <Child v-model="value" />
</template>
Equivalent to:
<template> 
    <Child :value="value" @ />
</template>
<!-- Subcomponents -->
<template>
	<input v-model="input" />
</template>
<script>
export default {
  props: {
    value: String,
  },
  model: {
    prop: 'value',		// Specify the name of the parameters to be bound by v-model, which comes from the parameters defined in props
    event: 'change',	// Specifies the name of the event to be triggered, which will be used for $emit
  },
  computed: {
    input: {
      // The calculation properties here use getter s and setter s, which can simplify the code
      // See links https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84-setter
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('change', val);	// trigger
      }
    }
  }
}
</script>

Seventh:. sync modifier

The function of v-model is similar to that of v-model. It is used for two-way binding. The difference is that v-model can only bind two-way for one data, only for the value value of input event, and the sync modifier has no restrictions

Example

<!-- Parent component -->
<template>
  <div id="app">
    <Numbers :num1.sync="n1" :num2.sync="n2" />
    <!-- Equivalent to -->
    <Numbers
      :num1="n1"
      @update:num1="n1 = $event"
      :num2="n2"
      @update:num2="n2 = $event"
    />
  </div>
</template>

<script>
import Numbers from "./components/Numbers.vue";

export default {
  components: {
    Numbers,
  },
  data() {
    return {
      n1: 0,
      n2: 0,
    };
  },
};
</script>

Eighth: $ref

The parent component can obtain instances of child components through ref

  • However, this practice is generally used only when necessary r e f , because by ref, because Ref, because ref will use real DOM operations, which is contrary to vue's concept of reducing manual operations on DOM elements

Cross component communication not limited to parent-child hierarchical relationship:

(brothers and brothers)

First: vuex

Data warehouse for large projects

Second: store mode

Data warehouse for small and medium-sized projects

// store.js
const store = {
  loginUser: ...,
  setting: ...
}

// compA
const compA = {
  data(){
    return {
      loginUser: store.loginUser
    }
  }
}

// compB
const compB = {
  data(){
    return {
      setting: store.setting,
      loginUser: store.loginUser
    }
  }
}

The third: eventbus

The component notifies the event bus that something has happened, and the event bus notifies all other components listening to the event to run a function (publish subscribe mode)

// send message
EventBus.$emit(channel: string, callback(payload1,...))
 
// Listen for received messages
EventBus.$on(channel: string, callback(payload1,...))

Its working principle is the publish / subscribe method, commonly known as Pub/Sub.

var EventBus = new Vue();
Object.defineProperties(Vue.prototype, {
  $bus: {
    get: function () {
      return EventBus
    }
  }
})

Two methods $on and $emit are used in this particular bus. An event used to create an issue is $emit; Another for subscription $on:

var EventBus = new Vue();
this.$bus.$emit('nameOfEvent', { ... pass some event data ...});
this.$bus.$on('nameOfEvent',($event) => {
  // ...
})

Then we can use this.$bus.$emit("sendMsg", 'I'm a web show') on a Vue page;, Another Vue page uses

this.$bus.$on('updateMessage', function(value) {
    console.log(value); // I'm a web show
})

You can also use this.$bus.$off('sendMsg ') to remove event listening.

The fourth type: router

If a component changes the address bar, all components listening to the address bar will respond accordingly

The most common scenario is to change the address by clicking the router link component, and the router view component renders other content

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-jlspt6zj-1638695654116) (C: \ users \ Dell \ appdata \ roaming \ typora \ user images \ image-20211205165438397. PNG)]

Note related codes:

Parent component:

<template>
  <div class="parent-root">
    <child
      class="child"
      :name="name"
      :age="age"
      :data="data"
      @change="change"
      @childEvent="childEvent"
    >
    </child>
    <p>Value passed by the sub component:{{ text }}</p>
  </div>
</template>
<script>
import child from "@/components/child";
export default {
  name: "parent",
  components: { child},
  provide: {
    foo: "bar",
  },
  data() {
    return {
      name: "Xiao Ming",
      age: 18,
      text: "",
      data: "me",
    };
  },

  computed: {},
  created() {},
  methods: {
    //Events passed by the sun component
    change(text) {
      this.text = text;
    },
    childEvent(name) {
      console.log("name:", name);
    },
  },
};
</script>


<style scoped lang="less">
.parent-root {
  padding: 20px;
  font-size: 16px;
  position: absolute;
  p {
    margin-bottom: 10px;
  }
}
</style>

Subcomponents:

<template>
  <div class="child-root">
    <grandchild v-bind="$attrs" v-on="$listeners"> </grandchild>
    <br />
    <button @click="childEvent">Of subcomponents childEvent</button>
    <br />
    For sub assembly props Yes data Data: {{ data }}
  </div>
</template>

<script>
import grandchild from "@/components/grandchild";
export default {
  name: "child",
  components: { grandchild },
  inject: ["foo"], 
  props: ["data"],
  //inheritAttrs:
  //The default value is true, and the attribute value will be automatically on the mounted component element. If props declares an attribute, the undeclared attribute will be mounted
  //When false, the attribute automatically mounted on the component root element is turned off
  inheritAttrs: false,

  data() {
    return {};
  },
  computed: {},
  created() {
    console.log(this.foo);
    console.log("$attrs:", this.$attrs, "$listeners:", this.$listeners); //$attrs: {"name": "Xiao Ming", "age": 18}, and "class":"child" will not be output here
  },
  mounted() {
    console.log("parent:", this.$parent, "children:", this.$children);
  },
  methods: {
    childEvent() {
      console.log("child of data:", this.data);
    },
  },
};
</script>

<style scoped lang="less">
.child-root {
 border: 1px solid #ccc;
}
</style>

Sub assembly:

<template>
  <div class="grandchild-root">
    <p>name: {{name}}</p>
    <p>age: {{age}}</p>
    <p>data: {{data}}</p>
    <button @click="bindChange">Grandson Click to pass on to Grandpa</button>
  </div>
</template>
<script>
  export default {
    name: 'grandchild',
    components: {},
    props: {
      name: {
        type: String,
        default: ''
      },
      age:{
        type: Number,
        default: null
      },
      data:{
        type: String,
        default: null
      }
    },
    methods: {
      bindChange() {
        let text = 'Hello, Grandpa'
        this.$emit('change',text);
      }

    },
  };
</script>

Organize notes and read relevant articles:

vue communication:

https://blog.csdn.net/zhoulu001/article/details/79548350

https://blog.csdn.net/Dobility/article/details/110147985

https://blog.csdn.net/weixin_42211816/article/details/116529864

v-model principle:

https://blog.csdn.net/yun_hou/article/details/86313212

https://blog.csdn.net/weixin_42380658/article/details/86568666

Modifier:

https://blog.csdn.net/qq_29468573/article/details/80771625

Event bus:

https://blog.csdn.net/i168wintop/article/details/95107935

Posted by Bullit on Sun, 05 Dec 2021 19:41:21 -0800