【Vue3】组件通信

news2024/12/27 12:30:52

Vue3组件通信和Vue2的区别:

  • 移出事件总线,使用mitt代替。
  • vuex换成了pinia
  • .sync优化到了v-model里面了。
  • $listeners所有的东西,合并到$attrs中了。
  • $children被砍掉了。

在这里插入图片描述

1. props

  • 父传子:属性值是非函数
  • 子传父:属性值是函数

父组件:

<template>
  <div class="father">
    <h3>--父组件,</h3>
    <h4>我的车:{{ car }}</h4>
    <h4>儿子给的玩具:{{ toy }}</h4>
    <Son
      :car="car"
      :getSonToy="getSonToy"
    />
  </div>
</template>

<script setup lang="ts">
import Son from './Son.vue'
import { ref } from "vue";
// 数据
const car = ref('奔驰')
const toy = ref()
// 方法
function getSonToy(value: string) {
  toy.value = value
}
</script>

子组件:

<template>
  <div class="child">
    <h3>--子组件--</h3>
    <h4>我的玩具:{{ toy }}</h4>
    <h4>父给我的车:{{ car }}</h4>
    <button @click="getSonToy(toy)">玩具给父亲</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const toy = ref('奥特曼')

defineProps(['car', 'getSonToy'])
</script>

在这里插入图片描述

2. 自定义事件

常用于:子 => 父

原生事件:

  • 事件名是特定的(clickmosueenter等等)
  • 事件对象$event: 是包含事件相关信息的对象(pageXpageYtargetkeyCode

自定义事件:

  • 事件名是任意名称
  • 事件对象$event: 是调用emit时所提供的数据,可以是任意类型

父组件:

<template>
  <div class="father">
    <h3>--父组件,</h3>
    <h4>我的车:{{ car }}</h4>
    <h4>儿子给的玩具:{{ toy }}</h4>
    <Son
      @get-son-toy="getSonToy"
    />
  </div>
</template>

<script setup lang="ts">
import Son from './Son.vue'
import { ref } from "vue";
// 数据
const car = ref('奔驰')
const toy = ref()
// 方法
function getSonToy(value: string) {
  toy.value = value
}
</script>

子组件:

<template>
  <div class="child">
    <h3>--子组件--</h3>
    <h4>我的玩具:{{ toy }}</h4>
    <!-- <h4>父给我的车:{{ car }}</h4> -->
    <button @click="emit('get-son-toy', toy)">玩具给父亲</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const toy = ref('奥特曼')

const emit = defineEmits(['get-son-to:y'])
</script>

在这里插入图片描述

扩展一个知识点:$event

<template>
  <div class="child">
    <h3>--子组件--</h3>
    <h4>我的玩具:{{ toy }}</h4>
    <!-- <h4>父给我的车:{{ car }}</h4> -->
    <!-- <button @click="emit('get-son-toy', toy)">玩具给父亲</button> -->
    <button @click="test('1', $event)">test</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const toy = ref('奥特曼')

// const emit = defineEmits(['get-son-toy'])
const test = (a: string, e: Event) => {
  console.log(a, e);
}
</script>

image.png

$event 为事件对象。

3. mitt

任意组件之间通信。

emitter.ts

// 引入mitt 
import mitt from "mitt";

// 创建emitter
const emitter = mitt()

/*
  // 绑定事件
  emitter.on('abc',(value)=>{
    console.log('abc事件被触发',value)
  })
  emitter.on('xyz',(value)=>{
    console.log('xyz事件被触发',value)
  })

  setInterval(() => {
    // 触发事件
    emitter.emit('abc',666)
    emitter.emit('xyz',777)
  }, 1000);

  setTimeout(() => {
    // 清理事件
    emitter.all.clear()
  }, 3000); 
*/

// 创建并暴露mitt
export default emitter

子组件:

<template>
  <div class="child">
    <h3>--子组件--</h3>
    <h4>我的玩具:{{ toy }}</h4>
    <button @click="emitter.emit('send-toy', toy)">玩具给父亲</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import emitter from '../utils/emitter'
const toy = ref('奥特曼')


</script>

父组件:

<template>
  <div class="father">
    <h3>--父组件,</h3>
    <h4>我的车:{{ car }}</h4>
    <h4>儿子给的玩具:{{ toy }}</h4>
    <Son/>
  </div>
</template>

<script setup lang="ts">
import Son from './Son.vue'
import { ref, onUnmounted } from "vue";
import emitter from '../utils/emitter'

// 数据
const car = ref('奔驰')
const toy = ref()
// 绑定事件
emitter.on('send-toy', (data) => {
  toy.value = data
  console.log('send-toy事件被触发', data)
})

onUnmounted(() => {
  // 解绑事件
  emitter.off('send-toy')
})
</script>

image.png

4. v-model

组件库底层父子传参常用。

MyInput 组件:

<template>
  <div class="box">
    <input
      type="text"
      :value="modelValue"
      @input="emit('update:modelValue', (<HTMLInputElement>$event.target).value)"
    >
  </div>
</template>

<script setup lang="ts">
// 接收props
defineProps(['modelValue'])
// 声明事件
const emit = defineEmits(['update:modelValue'])
</script>

父组件:

<template>
  <div class="father">
    <h3>--父组件--</h3>
    <MyInput v-model="username"/>
    <!-- 原理: -->
    <!-- <MyInput :modelValue="username" @update:modelValue="username = $event"/> -->
  </div>
</template>

<script setup lang="ts">
import MyInput from './MyInput.vue'
import {ref} from 'vue'
const username = ref('name')
</script>

image.png

  • 对于原生事件, $event就是事件对象=====>能使用.target
  • 对于自定义事件,$event就是触发事件时,所传递的数据==>不能.target

此外,还可以进行部分自定义修改:

父组件:

<MyInput v-model:myname="username"/>

MyInput 组件:

<template>
  <div class="box">
    <input
      type="text"
      :value="myname"
      @input="emit('update:myname', (<HTMLInputElement>$event.target).value)"
    >
  </div>
</template>

<script setup lang="ts">
// 接收props
defineProps(['myname'])
// 声明事件
const emit = defineEmits(['update:myname'])
</script>

5. $attrs

用于祖孙传参。

具体说明:$attrs是一个对象,包含所有父组件传入的标签属性。

$attrs会自动排除props中声明的属性

Father.vue

<template>
  <div class="father">
    <h3>--Father--</h3>
    <div>a: {{ a }}</div>
    <div>b: {{ b }}</div>
    <Son :a="a" :b="b" :addA="addA"  v-bind="{x: 100, y: 200}" ></Son>
  </div>
</template>

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

const a = ref(1)
const b = ref(2)

const addA = (data: number)=> {
  a.value += data
}

</script>

Son.vue

<template>
  <div class="box">
    <h3>--Son--</h3>
    <div>a: {{ a }}</div>
    <GrandSon v-bind="$attrs"/>
  </div>
</template>

<script setup lang="ts">
import GrandSon from './GrandSon.vue';

defineProps(['a'])
</script>

GrandSon.vue

<template>
  <div class="box">
    <h3>--GrandSon--</h3>
    <div>b: {{ b }}</div>
    <div>x: {{ x }}</div>
    <div>y: {{ y }}</div>
    <button @click="addA(1)">点我将a加1</button>
  </div>
</template>

<script setup lang="ts">

defineProps(['b', 'x', 'y' ,'addA'])
</script>

image.png

image.png

6. $refs$parent

概述:

  • $refs用于 :父→子。
  • $parent用于:子→父。

原理如下:

属性说明
$refs值为对象,包含所有被ref属性标识的DOM元素或组件实例。
$parent值为对象,当前组件的父组件实例对象。

Father.vue

<template>
	<div class="father">
		<h3>父组件</h3>
		<h4>房产:{{ house }}</h4>
		<button @click="changeToy">修改Child1的玩具</button>
		<button @click="changeComputer">修改Child2的电脑</button>
		<button @click="getAllChild($refs)">让所有孩子的书变多</button>
		<Child1 ref="c1" />
		<Child2 ref="c2" />
	</div>
</template>

<script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import { ref, reactive } from "vue";
let c1 = ref()
let c2 = ref()

// 注意点:当访问obj.c的时候,底层会自动读取value属性,因为c是在obj这个响应式对象中的
// 解释了为什么refs[key].book等写法后面不加.value
/* let obj = reactive({
	a:1,
	b:2,
	c:ref(3)
})
let x = ref(4)

console.log(obj.a)
console.log(obj.b)
console.log(obj.c)
console.log(x) */


// 数据
let house = ref(4)
// 方法
function changeToy() {
	c1.value.toy = '小猪佩奇'
}
function changeComputer() {
	c2.value.computer = '华为'
}
function getAllChild(refs: { [key: string]: any }) {
	console.log(refs)
	for (let key in refs) {
		refs[key].book += 3
	}
}
// 向外部提供数据
defineExpose({ house })
</script>

<style scoped>
.father {
	background-color: rgb(165, 164, 164);
	padding: 20px;
	border-radius: 10px;
}

.father button {
	margin-bottom: 10px;
	margin-left: 10px;
}
</style>


Child1.vue

<template>
	<div class="child1">
		<h3>子组件1</h3>
		<h4>玩具:{{ toy }}</h4>
		<h4>书籍:{{ book }}</h4>
		<button @click="minusHouse($parent)">干掉父亲的一套房产</button>
	</div>
</template>

<script setup lang="ts" name="Child1">
import { ref } from "vue";
// 数据
let toy = ref('奥特曼')
let book = ref(3)

// 方法
function minusHouse(parent: any) {
	parent.house -= 1
}

// 把数据交给外部
defineExpose({ toy, book })

</script>

<style scoped>
.child1 {
	margin-top: 20px;
	background-color: skyblue;
	padding: 20px;
	border-radius: 10px;
	box-shadow: 0 0 10px black;
}
</style>

Child2.vue

<template>
	<div class="child2">
		<h3>子组件2</h3>
		<h4>电脑:{{ computer }}</h4>
		<h4>书籍:{{ book }}</h4>
	</div>
</template>

<script setup lang="ts" name="Child2">
import { ref } from "vue";
// 数据
let computer = ref('联想')
let book = ref(6)
// 把数据交给外部
defineExpose({ computer, book })
</script>

<style scoped>
.child2 {
	margin-top: 20px;
	background-color: orange;
	padding: 20px;
	border-radius: 10px;
	box-shadow: 0 0 10px black;
}
</style>

7. provide、inject

实现祖孙组件直接通信。

  • 在祖先组件中通过provide配置向后代组件提供数据
  • 在后代组件中通过inject配置来声明接收数据

Father 组件:

<template>
  <div class="father">
    <h3>父组件</h3>
    <h4>银子:{{ money }}万元</h4>
    <h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4>
    <Child/>
  </div>
</template>

<script setup lang="ts" name="Father">
  import Child from './Child.vue'
  import {ref,reactive,provide} from 'vue'

  let money = ref(100)
  let car = reactive({
    brand:'奔驰',
    price:100
  })
  function updateMoney(value:number){
    money.value -= value
  }

  // 向后代提供数据
  provide('moneyContext',{money,updateMoney})
  provide('car',car)

</script>

<style scoped>
  .father {
    background-color: rgb(165, 164, 164);
    padding: 20px;
    border-radius: 10px;
  }
</style>

GrandChild 组件:

<template>
  <div class="grand-child">
    <h3>我是孙组件</h3>
    <h4>银子:{{ money }}</h4>
    <h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4>
    <button @click="updateMoney(6)">花爷爷的钱</button>
  </div>
</template>

<script setup lang="ts" name="GrandChild">
  import { inject } from "vue";

  let {money,updateMoney} = inject('moneyContext',{money:0,updateMoney:(param:number)=>{}})
  let car = inject('car',{brand:'未知',price:0})
</script>

<style scoped>
  .grand-child{
    background-color: orange;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px black;
  }
</style>

8. pinia

【Pinia】快速入门及数据持久化-CSDN博客

9. slot

【Vue3】slot 插槽全家桶_vue 多个匿名slot-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1408882.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【解决】IntelliJ IDEA 重命名 Shift + F6 失效

IntelliJ IDEA 重命名 Shift F6 失效 问题解决 问题 Idea 重命名 Shift F6 &#xff0c;一直没反应 解决 调查发现原因是微软新版的输入法冲突了。需要设置【使用以前版本的微软拼音输入法】解决兼容性。 设置 -> 时间和语言 -> 区域 -> 语言选项 -> 键盘选项…

ELK之使用Grafana读取ES集群的Nginx日志进行分析展示

一、前提&#xff1a; 直通车 ------------>↓↓↓↓↓↓ 需要ES集群 https://blog.csdn.net/wdy_2099/article/details/125441436需要filebeat https://blog.csdn.net/wdy_2099/article/details/125445893需要logstash https://blog.csdn.net/wdy_2099/article/details/1…

技术变革下职业危机

方向一&#xff1a;技术变革 1.人工智能&#xff08;AI&#xff09;&#xff1a;AI技术的快速发展正在改变各个行业。AI在医疗诊断、金融分析、客户服务以及物流管理等方面都有广泛应用&#xff0c;提高了效率和准确性。但同时也引发了一些道德和道德问题&#xff0c;比如隐私…

Redis的五种常用数据类型详解及相关面试问题

目录 Redis的五种常用数据类型详解 简述 Redis五种基本数据类型 String字符串 常用命令 应用场景 Hash散列表 常用命令 使用场景 List链表 常用命令 应用场景 Set( 集合) 常用命令 应用场景 SortedSet( 有序集合) zset 常用命令介绍 应用场景 面试题常问的数…

【MySQL】打开科技创新的第一生产力

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-EtRkflNU19AGWAkT {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

景联文科技大模型数据集更新!教育题库新增高质量数学题、逻辑推理题及英文题

苏格拉底曾以“点燃火焰”的理念来诠释教育。随着大语言模型在教育中的不断应用&#xff0c;教育与AI的深度融合&#xff0c;让我们看到了“点燃火焰”的理念的更多可能性。 大语言模型可以通过与学生的互动&#xff0c;为他们提供个性化的学习体验&#xff0c;更好地满足学习需…

Maven简述

Maven是用于管理和构建Java项目的工具&#xff0c;提供了一套标准化的项目结构&#xff0c;提供了一套标准化的构建流程&#xff0c;提供了一套依赖管理机制&#xff0c;通过Maven使得所有IDE构建的项目结构完全一样&#xff0c;让项目可以通用。 项目名称下分为src 和 pom.xm…

差分进化算法求解基于移动边缘计算 (MEC) 的无线区块链网络的联合挖矿决策和资源分配(提供MATLAB代码)

一、优化模型介绍 在所研究的区块链网络中&#xff0c;优化的变量为&#xff1a;挖矿决策&#xff08;即 m&#xff09;和资源分配&#xff08;即 p 和 f&#xff09;&#xff0c;目标函数是使所有矿工的总利润最大化。问题可以表述为&#xff1a; max ⁡ m , p , f F miner …

Linux系统SSH远程管理服务

目录 一、SSH服务介绍 1、SSH协议是什么&#xff1f; 2、SSH的优点 3、SSH的客户端与服务端 4、SSH的原理 4.1 公钥首次连接原理 4.2 ssh加密通讯原理 4.2.1 对称加密 4.2.2 非对称加密 4.2 ssh远程登录 二、服务端配置 1、常见配置项 1.1 修改默认端口 1.2 禁止…

Transformer and Pretrain Language Models3-1

content transformer attention mechanism transformer structure​​​​​​​ pretrained language models language modeling pre-trained langue models(PLMs&#xff09; fine-tuning approaches PLMs after BERT applications of masked LM frontiers of PLMs …

【Godot4自学手册】第四节动画状态机-AnimationTree

各位同学大家好&#xff01;今天继续学习Godot4&#xff0c;本节将要学习AnimationTree&#xff0c;来实现控制主人公的动画。 一、AnimationPlay节点介绍 Godot引擎通过AnimationPlay节点实现了最灵活的动画系统&#xff0c;它几乎可以给godot中的任意节点的任意属性添加动画…

携程基于Jira Cloud的敏捷项目管理实践

好的工具可以满足团队在各个成长阶段的管理诉求 实践一&#xff1a;对齐目标/团队OKR/多团队协作战略项目 实践二&#xff1a;以产品为中心的协作框架 实践三&#xff1a;交付团队管理 实践四&#xff1a;和海外子公司对齐&#xff0c;协作

数灵通丨可以实现抖音引流微信小程序了

抖音作为一款火爆的短视频社交平台&#xff0c;吸引了数亿用户的关注和喜爱。除了观看和制作视频外&#xff0c;抖音还提供了跳转到小程序的功能&#xff0c;让用户可以享受更多功能和乐趣。那么&#xff0c;如何在抖音中跳转到小程序呢&#xff1f;以下是详细解答&#xff1a;…

Android 基础技术——View 的宽高

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于 View 的宽高 Activity Resume 的时候设置或者获取view的宽高是否有效? 回答&#xff1a;不确定。 首次 onResume 无效&#xff0c;二次 onResume 就有效了。 回顾「Android 基础技术——addView 流…

[Python] glob内置模块介绍和使用场景(案例)

Unix glob是一种用于匹配文件路径的模式&#xff0c;它可以帮助我们快速地找到符合特定规则的文件。在本文中&#xff0c;我们将介绍glob的基本概念、使用方法以及一些实际应用案例。 glob介绍 Glob(Global Match)是Unix和类Unix系统中的一种文件名扩展功能&#xff0c;它可以…

eNSP学习——理解交换机Hybird接口的应用

目录 原理概述 实验内容 实验目的 实验步骤 实验拓扑 实验编址 实验步骤 基本配置&#xff08;此处仅以PC1为例&#xff09; 实现组内通信、组间间隔 实现网络管理员对所有网络的访问 原理概述 Hybrid接口既可以连接普通终端的接入链路又可以连接交换机间的干道…

嵌入式面试提问

嵌入式面试问题 1.讲一下STM32的时钟系统 现总结下&#xff1a;首先是时钟源输入时钟信号到单片机&#xff0c;然后单片机对输入的时钟信号进行倍频和分频处理&#xff0c;再将处理后的时钟信号输出至系统&#xff0c;外设或外部接口。   先看这张图&#xff0c;最外面的线上…

[docker] Docker资源管理

一、docker资源控制 Docker通过Cgroup 来控制容器使用的资源配额&#xff0c;包括CPU、内存、磁盘三大方面&#xff0c;基本覆盖了常见的资源配额和使用量控制。Caroup 是ControlGroups的缩写&#xff0c;是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如…

[linux] 域名解析失败案例定位 [Errno -2] Name or service not known

首先发现代码里这段运行报错&#xff1a; socket.gethostbyname_ex(host_name) Traceback (most recent call last): File “”, line 1, in socket.gaierror: [Errno -2] Name or service not known import socket host_name socket.gethostname() print(socket.gethostby…

CSS3基础知识总结

目录 一、CSS3 边框 1.border-radius&#xff1a;圆角边框 2.box-shadow&#xff1a;添加阴影 3.border-image&#xff1a;图片边框 二、CSS3 渐变 1.线性渐变(Linear Gradients) a.由上到下&#xff08;默认&#xff09; b.从左到右 c.对角 d.使用角度 2.径向渐变(…