This is the second day of my participation in the First Challenge 2022

Hello everyone, I am a bowl week, a front end that does not want to be drunk (inrolled). If I am lucky enough to write an article that you like, I am very lucky

Writing in the front

This article uses the

This article will introduce the following seven component communication modes:

  • props
  • emit
  • v-model
  • refs
  • provide/inject
  • eventBus
  • Vuex/Pinia (Status Management Tool)

Start doing things

Give me a chestnut

As the saying goes, learning not to write demo, that is playing rogue ~

This article will focus on the following demo, as shown below:

In the figure above, the list and input fields are parent components, which may vary depending on how values are passed.

Props way

The Props mode is one of the most common parent-to-child methods in Vue, and it is relatively simple to use.

Based on the demo above, we define the data and operations on the data in the parent component, and the child component does only one rendering of the list;

The parent component code is as follows:

<template>
  <! -- Subcomponent -->
  <child-components :list="list"></child-components>
  <! -- Parent component -->
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="Please enter"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">add</button>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript'.'HTML'.'CSS'])
const value = ref(' ')
// add the event handler after the trigger
const handleAdd = () = > {
  list.value.push(value.value)
  value.value = ' '
}
</script>

Copy the code

The child component only needs to render the value passed by the parent component as follows:

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in poops.list" :key="i">{{ i }}</li>
  </ul>
</template>
<script setup>
import { defineProps } from 'vue'
const poops = defineProps({
  list: {
    type: Array.default: () = >[],}})</script>

Copy the code

Emit way

Emit mode is also the most common component communication mode in Vue, which is used for child to parent communication.

Based on the demo above, we define the list in the parent component, and the child component just needs to pass the added value.

The sub-component code is as follows:

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="Please enter"
    />
    <div class="input-group-append">
      <button @click="handleSubmit" class="btn btn-primary" type="button">add</button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const value = ref(' ')
const emits = defineEmits(['add'])
const handleSubmit = () = > {
  emits('add', value.value)
  value.value = ' '
}
</script>
Copy the code

After clicking the Add button in the child component, emit a custom event and pass the added value as a parameter.

The parent component code is as follows:

<template>
  <! -- Parent component -->
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
  <! -- Subcomponent -->
  <child-components @add="handleAdd"></child-components>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript'.'HTML'.'CSS'])
// add the event handler after the trigger
const handleAdd = value= > {
  list.value.push(value)
}
</script>

Copy the code

In the parent component, you only need to listen for the child component’s custom events and then perform the corresponding add operations.

V – model

V-model is one of the better syntactic sugar in Vue, as shown in this code

<ChildComponent v-model:title="pageTitle" />

Copy the code

This is the shorthand situation for this code

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Copy the code

The V-Model is a lot easier, so let’s look at the demo above and see how it works with v-Model.

Child components

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="Please enter"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">add</button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineEmits, defineProps } from 'vue'
const value = ref(' ')
const props = defineProps({
  list: {
    type: Array.default: () = >[],}})const emits = defineEmits(['update:list'])
// Add operations
const handleAdd = () = > {
  const arr = props.list
  arr.push(value.value)
  emits('update:list', arr)
  value.value = ' '
}
</script>

Copy the code

In the child component we first define props and emits, and then emit the specified event after adding.

Note: update:* is a fixed notation in Vue, and * represents the name of an attribute in props.

The parent component is relatively simple to use, the code is as follows:

<template>
  <! -- Parent component -->
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
  <! -- Subcomponent -->
  <child-components v-model:list="list"></child-components>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript'.'HTML'.'CSS'])
</script>

Copy the code

Refs way

When using the optional API, we can get the specified element or component through this.$refs.name, but we can’t get either way in the composite API. If we want to get a component or element from a REF, we need to define a ref object with the same name that is accessible after the component is mounted.

Example code is as follows:

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in childRefs? .list" :key="i">
      {{ i }}
    </li>
  </ul>
  <! <script> < ref >
  <child-components ref="childRefs"></child-components>
  <! -- Parent component -->
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const childRefs = ref(null)
</script>

Copy the code

The sub-component code is as follows:

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="Please enter"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">add</button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineExpose } from 'vue'
const list = ref(['JavaScript'.'HTML'.'CSS'])
const value = ref(' ')
// add the event handler after the trigger
const handleAdd = () = > {
  list.value.push(value.value)
  value.value = ' '
}
defineExpose({ list })
</script>

Copy the code

The Setup component is off by default, that is, a public instance of the component retrieved from the template ref does not expose any bindings declared in **

Dojo.provide/inject way

Provide and Inject are a pair of apis provided in Vue that enable parent components to pass data to child components, no matter how deep the hierarchy. The sample code looks like this:

The parent component

<template>
  <! -- Subcomponent -->
  <child-components></child-components>
  <! -- Parent component -->
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="Please enter"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">add</button>
    </div>
  </div>
</template>
<script setup>
import { ref, provide } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript'.'HTML'.'CSS'])
const value = ref(' ')
// Provide data to child components
provide('list', list.value)
// add the event handler after the trigger
const handleAdd = () = > {
  list.value.push(value.value)
  value.value = ' '
}
</script>

Copy the code

Child components

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
</template>
<script setup>
import { inject } from 'vue'
// Accept the data provided by the parent
const list = inject('list')
</script>
Copy the code

Event bus

The event bus is removed in Vue3, but can be accomplished with the help of third-party tools. Mitt or Tiny-Emitter is officially recommended by Vue.

In most cases, it is not recommended to use the global event bus to implement component communication. Although it is relatively simple and crude, maintaining the event bus is a big problem in the long run, so I will not explain it here. For details, you can read the documentation of the specific tool

Status management tool

Vuex and Pinia are state management tools in Vue3. It is easy to use these two tools to realize component communication. Because these two tools have more powerful functions, they are not shown here

Write in the last

This is the end of this article, in general, relatively simple, nothing complex content.

If this article is useful to you, please like it, comment on it, and bookmark it to avoid missing it when you need it.

If there are any mistakes in this article, please correct them