Communication methods between Vue3 components

 

Table of contents

 1. props parent to child component communication

2. Custom event child communicates with parent component

3. Global event bus

4. v-model component communication (parent-child component data synchronization)

Bind a single data synchronization 

Bind multiple data synchronization 

5. useAttrs component communication

 6.ref and $parent

ref gets the subcomponent instance object

 $parent gets the parent component instance object

 7.provide-inject can realize intergenerational transmission

8. Pineapple

Selective API:

Composition API:


When we use Vue3 to develop projects, one of the problems we often need to face is the communication between components. How to send data to the corresponding components is an inevitable problem. This article describes the 8 main communication methods of Vue3. (others can be added)

 1. props parent to child component communication

parent component:

props is used by the parent component to pass data to the child component, and the child component uses defineProps to receive the parameters passed by the parent component

In the parent component, we can pass props data to the child component when using it

<Child info="父组件" v-bind:money="10000"></Child>

The data that does not use v-bind is fixed data, and if v-bind is used, it is dynamic data

Subassembly:

Receive data in child component

//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info', 'money'])

This method is a simple way of writing, and there is another way of writing objects, which has more usages, and can specify data types and default values/

let props = defineProps({
  info: {
    type: String,
    required: true, //是否规定必须得有
    default: 'info默认值'
  },
  money: {
    type: Number,
    required: true, //是否规定必须得有
    default: 9999  //默认数据,当父组件没有传递数据时,读取该数据
  }

It is also very simple to use in subcomponents (both methods are available)

    <p>{
   
   {props.info}}</p>
    <p>{
   
   {props.money}}</p>
    <!--props可以省略前面的名字--->
    <p>{
   
   {info}}</p>
    <p>{
   
   {money}}</p>

Note: the data of props is read-only and cannot be modified

2. Custom event child communicates with parent component

parent component

Receive custom events in the parent component

<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
<Event2 @xxx="handler3"></Event2>
//事件回调---4
const handler3 = (val1, val2) => {
  console.log(val1, val2)
}

Subassembly

Mainly, subcomponents use the defineEmits method to return functions to trigger custom events

//利用defineEmits方法返回函数触发自定义事件
//defineEmits方法不需要引入直接使用
let $emit = defineEmits(['xxx'])

Binding event passing parameters

<button @click="handler">点击我触发自定义事件xxx</button>

//按钮点击回调
const handler = () => {
  //第一个参数:事件类型 第二个|三个|N参数即为注入数据
  $emit('xxx', 'data1', 'data2')
}

When the button is clicked, the data will be passed to the parent component, and the parent component will receive the corresponding parameters

3. Global event bus

Because in Vue3, its vue constructor is removed, so it has no VM and cannot achieve the $bus global event bus. To implement the global event bus, you can use the mitt plug-in to achieve it .

mitt can be installed in the project

npm install --save mitt

In components that need to pass data, the $bus.emit method is to pass data

//引入$bus对象
import mitt from 'mitt'
const $bus = mitt()
//点击按钮回调
const handler = () => {
  $bus.emit('car', { car: '法拉利' })
}

 In the component receiving data, $bus.on is the method of receiving data

import mitt from 'mitt'
const $bus = mitt()

//组合式API函数
import { onMounted } from 'vue'
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
  //第一个参数:即为事件类型  第二个参数:即为事件回调
  $bus.on('car', (car) => {
    console.log(car)
  })
})

4. v-model component communication (parent-child component data synchronization)

Everyone's impression of v-model may be that it can be used to realize the two-way binding of form data, but in fact it can also be used to realize the data synchronization of parent and child components

Bind a single data synchronization 

If we don't use v-model, if we want to synchronize the data of parent and child components, we can use props and custom events at the same time, as follows:

parent component:

//props:父亲给儿子数据
<Child :modelValue="money" @update:modelValue="handler"></Child>

<script setup lang="ts">
import Child from './Child.vue'
import { ref } from 'vue'
let money = ref(10000)
//自定义事件的回调
const handler = (num) => {
  //将来接受子组件传递过来的数据
  money.value = num
}
</script>

Subassembly:

<template>
  <div class="child">
    <h3>钱数:{
   
   { modelValue }}</h3>
    <button @click="handler">父子组件数据同步</button>
  </div>
</template>

<script setup lang="ts">
//接受props
let props = defineProps(["modelValue"]);
let $emit = defineEmits(['update:modelValue']);
//子组件内部按钮的点击回调
const handler = ()=>{
   //触发自定义事件
   $emit('update:modelValue',props.modelValue+1000);
}
</script>

It can be seen that we need to use props and custom events at the same time to achieve data synchronization between parent and child components

Using v-model is to achieve:

Just modify the label of the subcomponent

<Child v-model="money"></Child>

       v-model is used on components

       1: It is quite necessary to pass props[modelValue] = 10000 to the child component

       2: It is equivalent to binding a custom event update:modelValue to the subcomponent

Bind multiple data synchronization 

parent component:

<Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
//父亲的数据
let pageNo = ref(1)
let pageSize = ref(3)

The child component receives:

<template>
  <div class="child2">
    <h1>同时绑定多个v-model</h1>
    <button @click="handler">pageNo{
   
   { pageNo }}</button>
    <button @click="$emit('update:pageSize', pageSize + 4)">
      pageSize{
   
   { pageSize }}
    </button>
  </div>
</template>

<script setup lang="ts">
let props = defineProps(["pageNo", "pageSize"]);
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
//第一个按钮的事件回调
const handler = () => {
  $emit("update:pageNo", props.pageNo + 3);
};
</script>

The main implementation principle is still using the combination of props and custom events, v-model just helps us synchronize data and methods

5. useAttrs component communication

Parent component: pass the message property to the child component

<template>
  <div>
    <input v-model="message">
    <HidtButton :message="message" />
  </div>
</template>

<script setup lang="ts">
import HidtButton from './HintButton.vue'
import { ref } from 'vue'

const message = ref('')
</script>

Subcomponent: receive and display data with useAttrs

<template>
  <div>
    <p>{
   
   { $attrs.message }}</p>
  </div>
</template>

<script setup lang="ts">
import { useAttrs } from 'vue'
let $attrs = useAttrs()
console.log($attrs)
</script>

useAttrs can receive the attributes of the parent component

In this way, the child component receives the data of the parent component

The function of useAttrs is very similar to that of props. Both parent components pass data to child components. If props and useAttrs are used to receive data at the same time, props has a higher priority than useAttrs

 6.ref and $parent

ref gets the subcomponent instance object

ref: You can get the real DOM node, you can get the subcomponent instance VC, and get the subcomponent instance in the parent component, then you can manipulate the properties and methods of the subcomponent, which cannot be obtained by default. Components need to be exposed to the outside world

parent component:

<template>
  <div class="box">
    <h1>我是父组件:{
   
   {money}}</h1>
    <button @click="handler">找我的儿子借10元</button>
    <Son ref="son"></Son>
  </div>
</template>

<script setup lang="ts">
//ref:可以获取真实的DOM节点,可以获取到子组件实例VC
//$parent:可以在子组件内部获取到父组件的实例
//引入子组件
import Son from './Son.vue'
import { ref } from 'vue'
//父组件钱数
let money = ref(100000000)
//获取子组件的实例
let son = ref()
//父组件内部按钮点击回调
const handler = () => {
  console.log(son.value)//打印子组件的实例对象
  money.value += 10
  //儿子钱数减去10
  son.value.money -= 10
  son.value.fly()
}
})

 Subassembly:

<template>
  <div class="son">
    <h3>我是子组件:{
   
   {money}}</h3>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
//儿子钱数
let money = ref(666)
const fly = () => {
  console.log('我可以飞')
}
//组件内部数据对外关闭的,别人不能访问
//如果想让外部访问需要通过defineExpose方法对外暴露
defineExpose({
  money,
  fly
})
</script>

The instance object of the child component: 

 $parent gets the parent component instance object

$parent: The instance of the parent component can be obtained inside the child component

The parent component only needs to put the child component:

<Dau></Dau>
<script setup lang="ts">
//$parent:可以在子组件内部获取到父组件的实例
//引入子组件
import Dau from './Daughter.vue'
import { ref } from 'vue'
//父组件钱数
let money = ref(100000000)
//对外暴露
defineExpose({
  money
)}
</script>

In the child component, use $parent to get the instance object of the parent component. Of course, our parent component also needs to be exposed to the outside world so that the child component can get the instance object

<template>
  <div class="dau">
    <h1>我是子组件{
   
   {money}}</h1>
    <button @click="handler($parent)">点击我父组件给我10000元</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
//子组件钱数
let money = ref(999999)
//子组件按钮点击回调
const handler = ($parent: any) => {
  console.log($parent)
  money.value += 10000
  $parent.money -= 10000
}
</script>

Use the click event to inject $parent to get the father's instance object

 7.provide-inject can realize intergenerational transmission

Parent component: use provide to transmit the corresponding data, and provide a key, and subsequent subcomponents also use this key to get data

<template>
  <div class="box">
    <h1>Provide与Inject{
   
   {car}}</h1>
    <hr />
    <Child></Child>
  </div>
</template>

<script setup lang="ts">
import Child from "./Child.vue";
//vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
import { ref, provide } from "vue";
let car = ref("法拉利");
//祖先组件给后代组件提供数据
//两个参数:第一个参数就是提供的数据key
//第二个参数:祖先组件提供数据
provide("TOKEN", car);
</script>

Subcomponent: use inject and the corresponding key to get the corresponding data

<template>
  <div class="child">
    <h1>我是子组件1{
   
   { car }}</h1>
    <Child></Child>
  </div>
</template>

<script setup lang="ts">
import Child from './GrandChild.vue'
import { inject } from 'vue'
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('TOKEN')
</script>

Grandson component: data can be modified, and all component data is synchronized

<template>
  <div class="child1">
    <h1>孙子组件</h1>
    <p>{
   
   {car}}</p>
    <button @click="updateCar">更新数据</button>
  </div>
</template>

<script setup lang="ts">
import {inject} from 'vue';
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('TOKEN');
const updateCar = ()=>{
   car.value  = '自行车';
}
</script>

8. Pineapple

Compared with Vuex, Pinia provides a more concise and direct API, and provides a combined style API, and most importantly, it provides a more complete type deduction when using TypeScript.

This is also the reason why vue officially recommends the state centralized management tool

 Need to install its dependencies when using pinia

npm i pinia

 pinia can support vue2 and vue3, so there are two ways of writing, combination and selection

1. Create a new warehouse file store to create a large index.ts warehouse

//创建大仓库
import { createPinia } from 'pinia';
//createPinia方法可以用于创建大仓库
let store = createPinia();
//对外暴露,安装仓库
export default store;

2. Reference in mian.js

//引入仓库
import store from './store'
//使用
app.use(store)

Selective API:

state stores data

Actions implementation method (data can be modified in between)

getters computed properties

//定义info小仓库
import { defineStore } from "pinia";
//第一个仓库:小仓库名字  第二个参数:小仓库配置对象
//defineStore方法执行会返回一个函数,函数作用就是让组件可以获取到仓库数据
let useInfoStore = defineStore("info", {
    //存储数据:state
    state: () => {
        return {
            count: 99,
            arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        }
    },
    actions: {
        //注意:函数没有context上下文对象
        //没有commit、没有mutations去修改数据
        updateNum(a: number, b: number) {
            this.count += a;
        }
    },
    getters: {
       
    }
});
//对外暴露方法
export default useInfoStore;

Using pinia data in components

<template>
  <div class="child">
    <h1>{
   
   { infoStore.count }}---{
   
   {infoStore.total}}</h1>
    <button @click="updateCount">点击我修改仓库数据</button>
  </div>
</template>

<script setup lang="ts">
import useInfoStore from "../../store/modules/info";
//获取小仓库对象
let infoStore = useInfoStore();
console.log(infoStore);
//修改数据方法
const updateCount = () => {
  //仓库调用自身的方法去修改仓库的数据
  infoStore.updateNum(66,77);
};
</script>

Composition API:

//定义组合式API仓库
import { defineStore } from "pinia";
import { ref, computed } from 'vue';
//创建小仓库
let useTodoStore = defineStore('todo', () => {
    let arr = ref([1,2,3,4,5]);

    const total = computed(() => {
        return arr.value.reduce((prev, next) => {
            return prev + next;
        }, 0)
    })
    function updateTodo() {
        arr.value.push(0)
    }
    //务必要返回一个对象:属性与方法可以提供给组件使用
    return {
        arr,
        total,
        updateTodo
    }
});

export default useTodoStore;

In the component use:

<template>
  <div class="child1">
    <p @click="updateTodo">{
   
   { todoStore.arr }}</p>
  </div>
</template>

<script setup lang="ts">
//引入组合式API函数仓库
import useTodoStore from "../../store/modules/todo";
let todoStore = useTodoStore();

//点击p段落去修改仓库的数据
const updateTodo = () => {
  todoStore.updateTodo();
};
</script>

Guess you like

Origin blog.csdn.net/m0_64642443/article/details/131787640
Recommended