首页 > 其他分享 >vue 组件通信

vue 组件通信

时间:2023-03-26 21:00:32浏览次数:42  
标签:vue const counter component 通信 组件 import children

1. 子组件间通信(defineEmits + defineProps)

1.1 实现效果

在一个子组件的输入框中输入数据, 在另一个子组件上显示. 如下图:

1.2 defineEmits 和 defineProps 的 TS 使用

1.2.1 defineEmits 的 TS 使用

export declare function defineEmits<TypeEmit>(): TypeEmit;
// 根据上面的定义, 我们可以知道通过传入函数签名可以为其返回的 emit 方法定义类型, 对 emit 进行精确的类型定义
const emit = defineEmits<{
  (e: 'update-age', data: number): void
  (e: 'update-name', data: string): void
}>()

1.2.2 defineProps 的 TS 使用

export declare function defineProps<TypeProps>(): Readonly<Omit<TypeProps, BooleanKey<TypeProps>> & {
    [K in keyof Pick<TypeProps, BooleanKey<TypeProps>>]-?: NotUndefined<TypeProps[K]>;
}>;

/**
  * defineProps<{
  *   propName1: TSType,
  *   propName2: TSType,
  *   ......
  * }>()
  */

1.2.2.1 另外两种 JS 使用

export declare function defineProps<PropNames extends string = string>(props: PropNames[]): Readonly<{
    [key in PropNames]?: any;
}>;
// defineProps(['propName1', 'propName2', ...])
export declare function defineProps<PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions>(props: PP): Readonly<ExtractPropTypes<PP>>;

export declare type ComponentObjectPropsOptions<P = Data> = {
    [K in keyof P]: Prop<P[K]> | null;
};

export declare type Prop<T, D = T> = PropOptions<T, D> | PropType<T>;

declare interface PropOptions<T = any, D = T> {
    type?: PropType<T> | true | null;
    required?: boolean;
    default?: D | DefaultFactory<D> | null | undefined | object;
    validator?(value: unknown): boolean;
}

declare type Data = Record<string, unknown>;

/**
 * defineProps({
 *   propName1: {
 *     type: propName1Type,
 *     required: isRequired,
 *     default: defaultValue
 *   },
 *   propName2: propName2Type,
 *   ......
 * })
 */

1.3 具体实现

1.3.1 children-component-one

<!-- children-component-one --> 
<script setup lang="ts">
import { ref } from 'vue'

const inputValue = ref('')

const emit = defineEmits<{
  (e: 'update-input-text', data: string): void
}>()

const handleInput = () => {
  emit('update-input-text', inputValue.value)
}
</script>

<template>
  <div class="children-component-one">
    inputValue: <input type="text" v-model="inputValue" @input="handleInput" />
  </div>
</template>

1.3.2 children-component-two

<!-- children-component-two -->
<script setup lang="ts">
defineProps<{
  inputTextValue: string
}>()
</script>

<template>
  <div class="children-component-two">
    show: {{ inputTextValue }}
  </div>
</template>

1.3.3 parent-component

<!-- app.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import childrenComponentOne from './views/children-component-one.vue'
import childrenComponentTwo from './views/children-component-two.vue'

const inputText = ref('')

const inputTextUpdateHandle = (newValue: string) => {
  inputText.value = newValue
}
</script>

<template>
  <div class="app">
    <h2>app</h2>
    <children-component-one @update-input-text="inputTextUpdateHandle"/>
    <children-component-two :input-text-value="inputText" /> <!-- 父组件向子组件传值 -->
  </div>
</template>

通过 defineEmits 可以实现子组件向父组件传值

通过 defineProps 可以实现子组件接收父组件传来的值

两者配合即可实现子组件间的通信

2. 父子组件间的通信(v-model + defineEmits + defineProps)

2.1 实现效果

父组件有一计数器 counter , 子组件有一 button , 通过点击 button 可以使得 counter + 1 , 而 counter 的显示则交由父组件

2.2 具体实现

2.2.1 children-component

<script setup lang="ts">
const props = defineProps<{
  counter: number
}>()

const emit = defineEmits<{
  (e: 'update:counter', data: number): void
}>()

const handleClick = () => {
  emit('update:counter', props.counter + 1)
}
</script>

<template>
  <div class="children-component">
    <h2>children-component</h2>
    <button @click="handleClick">add one</button>
  </div>
</template>

2.2.2 parent-component

<script setup lang="ts">
import { ref } from 'vue'
import childrenComponent from '../children-component/children-component.vue'

const counter = ref(0)
</script>

<template>
  <div class="parent-component">
    <h2>parent-component</h2>
    Counter: {{ counter }}
    <children-component v-model:counter="counter" />
  </div>
</template>

3. 父子组件间的通信(ref + defineExpose)

3.1 实现效果

子组件中有一计数器 counter 和一个能令 counter + 1button , 且子组件将传递 counter 给父组件, 由父组件来进行展示. 如下图所示:

3.2 defineExpose 的 TS 使用

declare function defineExpose<Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed): void;

/**
 * const passValue: PassType = someValue
 * defineExpose(passValue)
 */

3.3 具体实现

3.3.1 parent-component

<script setup lang="ts">
import { ref, type Ref } from 'vue'
import childrenComponent from '../children-component/children-component.vue'
import type { PassType } from '@/types'

const passValue = ref({}) as Ref<PassType>
</script>

<template>
  <div class="parent-component">
    <h2>parent-component</h2>
    Counter: {{ passValue.counter }}
    <children-component ref="passValue" />
  </div>
</template>

3.3.2 children-component

<script setup lang="ts">
import { ref } from 'vue'
import type { PassType } from '@/types';

const counter = ref(0)

const handleClick = () => {
  counter.value++
}

const passValue: PassType = { counter }

defineExpose(passValue)
</script>

<template>
  <div class="children-component">
    <h2>children-component</h2>
    <button @click="handleClick">add one</button>
  </div>
</template>

3.3.3 src/types/index.ts

export interface PassType {
  counter: Ref<number>
}

4. 祖先-后代组件间的通信(Provide + Inject)

由祖先节点通过 Provide 提供需要传递的值, 而该节点的任何后代节点都可以通过 Inject 接收传递的值

4.1 实现效果

祖先组件拥有一个 counter 和一个可以令 counter + 1button, 并将 counter 传递给后代组件, 交由后代组件来进行展示

4.2 Provide + Inject 的 TS 使用

declare function provide<T>(key: InjectionKey<T> | string | number, value: T): void

declare function inject<T>(key: InjectionKey<T> | string): T | undefined

export declare interface InjectionKey<T> extends Symbol {}
// 由这行代码可知: InjectionKey<T> 类型可以接收 Symbol 类型的值
// 由上面的代码块可知
// 用法 1 :
const value: ValueType = someValue
const key: InjectionKey<ValueType> = Symbol('key-name')

provide(key, value)
const passValue: ValueType = inject(key)

// 用法 2:
const value: ValueType = someValue

provide('pass-value', value)
const passValue = inject<ValueType>('pass-value')

4.3 具体实现

4.3.1 src/types/index.ts

import type { InjectionKey, Ref } from 'vue'

export type CounterType = Ref<number>
export const key: InjectionKey<CounterType> = Symbol('CounterType')

4.3.2 祖先组件

<script setup lang="ts">
import { key } from '@/types';
import { provide, ref } from 'vue'
import childrenComponent from '../children-component/children-component.vue'

const counter = ref(0)
const handleClick = () => {
  counter.value++
}

provide(key, counter)
</script>

<template>
  <div class="parent-component">
    <h2>parent-component</h2>
    <button @click="handleClick">add one</button>
    <children-component />
  </div>
</template>

4.3.3 后代组件

<script setup lang="ts">
import { inject } from 'vue'
import { key } from '@/types/index'

const counter = inject(key)
</script>

<template>
  <div class="children-component">
    <h2>children-component</h2>
    Counter: {{ counter }}
  </div>
</template>

5. 状态管理工具(Pinia / Vuex)

标签:vue,const,counter,component,通信,组件,import,children
From: https://www.cnblogs.com/suzukaze/p/components-communication.html

相关文章

  • 去中心化组件共享方案 —— Webpack Module Federation(模块联邦)
    在大型应用中,我们可能会对其进行拆分,分成容器、主应用和多个子应用,使拆分后的应用独立开发与部署,更加容易维护。但无论是微应用、公共模块应用,都需要放到容器中才能使用。......
  • Vue进阶(二十八):浅析 Vue 中 computed 与 method 区别
    一、前言computed区别于method的两个点:computed是属性调用,而methods是函数调用;computed带有缓存功能,而methods不是;下面看一个具体例子:<!--HTML部分--><divid="ap......
  • 初入了解——Vue.js
    目录 前言:一.Vue.js介绍二.主要功能三.语言特点易用灵活性能版本记录: Vue3.xVue2.x Vue1.0 Vue0.12 Vue0.11四.运行环境 前言:根据上篇文章来继续了解Vue一.V......
  • web前端框架——Vue的特性
    目录前言: 一.vue二.特性1.轻量级2.数据绑定3.指令4.插件三.比较Angular、React、Vue框架之间的比较1.AngularAngular的优点:2.ReactReact的优点:3.vue3.Vue的优点:前言: ......
  • 摸索graphQL在前端vue中使用过程(三)
    上回说到,那个请求拦截的一个过程,我上次不会看官网教程,这次,终于有了新的发现。graphQL的interceptors(请求拦截器)importApolloClientfrom'apollo-boost';constapolloCl......
  • Vue核心 Vue简介 初识
     1.1.Vue简介 1.1.1.官网●英文官网●中文官网 1.1.2.介绍与描述●Vue是一套用来动态构建用户界面的渐进式JavaScript框架○构建用户界面:把数据通过某种办......
  • Vue核心 模板语法 数据绑定
    1.3.模板语法Vue模板语法包括两大类1插值语法功能:用于解析标签体内容写法:{{xxx}},xxx是js表达式,可以直接读取到data中的所有区域2指令语法功能:用于解析标签(包括:标签属......
  • Vue核心 el与data的两种写法
    1.5.el与data的两种写法el有2种写法a创建Vue实例对象的时候配置el属性b先创建Vue实例,随后再通过vm.$mount('#root')指定el的值data有2种写法a对象式:data:{}b函数式:dat......
  • Vue3的fetch和Axios
    Vue3的fetch和Axios都是用于发送HTTP请求的JavaScript库,但是它们之间有以下几个区别:语法不同:fetch是浏览器原生的API,使用起来比较简单,而Axios是一个第三方库,需要通过npm安......
  • vue.js客服系统实时聊天项目开发(十三)日期缩短展示,同一天只展示时秒,同一年展示月日小时
    客服系统中在展示聊天消息时间的时候,根据当前日期与目标日期的情况进行缩短显示,如果是同一天,只显示小时、分钟、秒,如果是同一年,只显示月日小时、分钟、秒,否则显示全部,根据这......