Vue3 component communication

Posted by engkeb0i on Mon, 20 Sep 2021 08:48:12 +0200

Vue3 component communication

1.props / $emit

The parent component passes data to the child component through props, and the child component can communicate to the parent component through $emit.

① Parent component passes value to child component
How to obtain the data in the parent component section.vue in the sub component article.vue articles: ['dream of Red Mansions',' journey to the West ',' romance of the three kingdoms']

The parent component declares the variable < com article: Articles = "articlelist" > < / COM article > in the child component, and the child component receives the data with props. props: ['articles']

// section parent component
<script>
 const app = Vue.createApp({
  data() {
    return {
      name: 'HelloWorld',
      articleList: ['The Dream of Red Mansion', 'Journey to the West', 'Romance of the Three Kingdoms']
    }
  },
  template:`
  <div class="section">
    <com-article :articles="articleList"></com-article>
  </div>
`})
app.component('comArticle',{
// Subcomponent article.vue
  props: ['articles'],
  template:`
  <div>
    <span v-for="(item, index) in articles" :key="index">{{item}}</span>
  </div>
`
})
</script>

② Child component passes value to parent component

$emit binds a custom event. When this statement is executed, it will pass the parameter arg to the parent component, which listens and receives the parameters through v-on.

Parent component v-on listens to receive parameter @ onEmitIndex="onEmitIndex", and child component $emit transmits data, this.$emit('onEmitIndex', index)

// In parent component
<script>
const app = Vue.createApp({
  data() {
    return {
      name: 'HelloWorld',
      currentIndex: -1,
      articleList: ['The Dream of Red Mansion', 'Journey to the West', 'Romance of the Three Kingdoms']
    }
  },
  template:`
  <div class="section">
    <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
    <p>{{currentIndex}}</p>
  </div>
`,
  methods: {
    onEmitIndex(idx) {
      this.currentIndex = idx
    }
  }
})
app.component('comArticle,',{
//Subcomponents
props: ['articles'],
template:`
  <div>
    <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
`,
  methods: {
    emitIndex(index) {
      this.$emit('onEmitIndex', index)
    }
  }
})

$children / $parent

① Parent component $parent

this.$children[0].messageA = 'this is new value'
// In parent component
<script>
const app = Vue.createApp({
  data() {
    return {
      name: 'HelloWorld',
      msg: 'Welcome'
    }
  },
template:`
  <div class="hello_world">
    <div>{{msg}}</div>
    <com-a></com-a>
    <button @click="changeA">Click to change the sub component value</button>
  </div>
`,
  methods: {
    changeA() {
      // Get sub component A
      this.$children[0].messageA = 'this is new value'
    }
  }
})
app.component('ComA,',{

})
</script>

② Subcomponent $parent

this.$parent.msg
// In subcomponents
app.component('ComA,',{
data() {
    return {
      messageA: 'this is old'
    }
  },
template:`
  <div class="com_a">
    <span>{{messageA}}</span>
    <p>Get the value of the parent component as:  {{parentVal}}</p>
  </div>
`,
computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
})

provide/ inject

provide/ inject yes vue2.2.0 New api, In simple terms, it means that the parent component provide To provide variables, Then pass through the sub components inject To inject variables.

Next, use an example to verify the above description: suppose there are three components: A.vue, B.vue and C.vue, where C is the sub component of B, B is the sub component of A, and A > > b > > C

Parent component provide Send data down( provide: {for: "demo"}),For sub assembly inject Use( inject: ['for'])
Vue2 code
// A.vue
<template>
  <div>
	<comB></comB>
  </div>
</template>

<script>
  import comB from '../components/test/comB.vue'
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>

// B.vue
<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</template>

<script>
  import comC from '../components/test/comC.vue'
  export default {
    name: "B",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    },
    components: {
      comC
    }
  }
</script>


// C.vue
<template>
  <div>
    {{demo}}
  </div>
</template>

<script>
  export default {
    name: "C",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    }
  }
</script>

$ref / $refs

$ref: if it is used on a common DOM element, the reference points to the DOM element; if it is used on a sub component, the reference points to the component instance. You can directly call the component's methods or access data through the instance

// Sub assembly A.vue
app.component('componentA',{
  data () {
    return {
      name: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      console.log('hello')
    }
  }
})

// Parent component app.vue
<template>
  <component-a ref="comA"></component-a>
</template>
<script>
const app = Vue.createApp({
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.name);  // Vue.js
      comA.sayHello();  // hello
    }
  }
</script>

evnetBus

EventBus, also known as event bus, can be used as a communication bridge in vue. It is like that all components share the same event center, which can register to send or receive events, so components can notify other components.

eventBus There are also inconveniences, When the project is large,It is easy to cause disasters that are difficult to maintain

① Initialization

First, you need to create an event bus and export it so that other modules can use or listen to it

// event-bus.js
const EventBus = new Vue()
Copy code

② Send event

// Send events in addionnum.vue
<template>
  <div>
    <button @click="additionHandle">+adder</button>    
  </div>
</template>

<script>
console.log(EventBus)
const app = Vue.createApp({
  data(){
    return{
      num:1
    }
  },
  methods:{
    additionHandle(){
      EventBus.$emit('addition', {
        num:this.num++
      })
    }
  }
}
</script>

③ Receive event

// Receive events in showNum.vue
<template>
  <div>Calculation and: {{count}}</div>
</template>
<script>
const app = Vue.createApp({
  data() {
    return {
      count: 0
    }
  },
  mounted() {
    EventBus.$on('addition', param => {
      this.count = this.count + param.num;
    })
  }
}
</script>

In this way, click the Add button in the component addionnum.vue, and use the passed num to display the sum result in showNum.vue

④ Remove event listener

EventBus.$off('addition', {})

VueX

Vuex is a state management mode specially developed for Vue.js applications. It uses centralized storage to manage the state of all components of the application, and ensures that the state changes in a predictable way with corresponding rules.

Vuex solves the problem that multiple views depend on the same state and the behavior from different views needs to change the same state, and focuses the developer's energy on the update of data rather than the transmission of data between components.

① Store data

 this.$store.commit('receiveBMsg', {
          BMsg: this.BMessage
        })
Copy code

② Read data

this.$store.state.BMsg

localStorage / sessionStorage

adopt window.localStorage.getItem(key)get data
 adopt window.localStorage.setItem(key,value)Store data

$attrs and $listeners

vm.$attrs contains attribute bindings (except class and style) that are not recognized (and obtained) as props in the parent scope. When a component does not declare any props, all parent scope bindings (except class and style) will be included here, and you can use v-bind="$attrs" Incoming internal components - useful when creating high-level components. vm.$listeners

Contains v-on event listeners in the parent scope (without. native modifiers). It can be passed in to internal components through v-on="$listeners" - very useful when creating higher-level components.

// app.vue
// index.vue
<template>
  <div>
    <child-com1
      :name="name"
      :age="age"
      :gender="gender"
      :height="height"
      title="Programmer growth points north"
    ></child-com1>
  </div>
</template>
<script>
const app = Vue.createApp({
  data() {
    return {
      name: "zhang",
      age: "18",
      gender: "female",
      height: "158"
    };
  }
};
</script>
// childCom1.vue
app.component('childCom1,',{
template:`
  <div>
    <p>name: {{ name}}</p>
    <p>childCom1 of $attrs: {{ $attrs }}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
`
})
inheritAttrs: false, // You can turn off properties that are not declared in props that are automatically mounted to the component root element
 props: {
    name: String // name is bound as props attribute
  },
  created() {
    console.log(this.$attrs);
     // {"age": "18", "gender": "female", "height": "158", "title": "programmer growth points north"}
  }
};
</script>

// childCom2.vue
app.components('childCom2',{
    template:`
  <div class="border">
    <p>age: {{ age}}</p>
    <p>childCom2: {{ $attrs }}</p>
  </div>
`,
inheritAttrs: false,
  props: {
    age: String
  },
  created() {
    console.log(this.$attrs); 
    // {"gender": "female", "height": "158", "title": "programmer growth points north"}
  }
}

summary

Parent child component communication:props; $parent/ $children; provide / inject ; ref ; $attrs / $listeners
 Sibling component communication: eventBus ; vuex
 Cross level communication: eventBus;Vuex;provide / inject ,$attrs / $listeners

Topics: Java Vue Vue.js