【Vue3】组件通信

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博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络协议与攻击模拟_08DHCP协议

技术学习要了解某项技术能干什么&#xff1f;它的详细内容&#xff1f;发展走向&#xff1f; 一、DHCP协议 1、DHCP基本概念 dhcp动态主机配置协议&#xff0c;广泛应用于局域网内部 主要是为客户机提供TCP/IP 参数&#xff08;IP地址、子网掩码、网关、DNS等&#xff09;…

【AI】深度学习与图像描述生成——看图说话(1)

还记得我闲来无事&#xff0c;用大模型来“洗图”吗&#xff0c;就是想抄袭别人的图&#xff0c;但是又要装作原创的样子。因为洗稿大家都熟悉&#xff0c;洗图其实也是一样的。 【AIGC】今天想用AI“洗个图”&#xff0c;失败了&#xff0c;进来看我怎么做的-CSDN博客 【AIG…

Vue3快速使用手册

Vue3的创建 npm create vitelatest 1.设置项目名。 2.选择框架。 3.选择支持的语法&#xff0c;默认使用TS。 ...... Vue3的使用 setUp(无法直接修改数据&#xff0c;也就是没有响应式) 在vue3中不不再推荐使用选项式编程而是使用组合式编程。 Vue2写法 <template…

matlab GUI实现PID控制器参数配置

1、内容简介 略 39-可以交流、咨询、答疑 2、内容说明 略 3、 基于GUI的PID研究 本例子中设计一个PID控制器来研究不同参数对输出结果的影响&#xff0c;PID控制器由比例单元 P、积分单元 I 和微分单元 D 组成。PID 控制器是一个在工业控制应用中常见的反馈回路部件&…

JavaEE之多线程编程:4. 线程安全(重点!!!)

文章目录 一、观察线程不安全二、线程安全的概念三、线程不安全的原因1. 关于线程不安全的解释1. 抢占式执行2. 修改共享数据3. 原子性4. 可见性5. 指令重排序问题 四、解决之前的线程不安全的问题五、synchronized 关键字&#xff08;两个线程同时修改一个变量&#xff09;1. …

特征抽取-----机器学习pycharm软件

导入包 from sklearn.datasets import load_iris # 方法datasets_demo()数据集使用 from sklearn.feature_extraction import DictVectorizer # 方法dict_demo()字典特征抽取用 from sklearn.feature_extraction.text import CountVectorizer # 方法count_demo()文本特征抽…

红外热成像 ~ 基于matlab的非均匀校正code

红外芯片由于工艺问题存在严重的分均匀性&#xff0c;所以非均匀矫正一直是影响红外图像质量的第一因素。分均匀矫正的算法也是红外图像处理研究的重点区域&#xff0c;建立了一些矫正的方式方法。其中最常用最简单的就应该算是两点温度定标算法。 应用两点法校正有两个前提条…

想要透明拼接屏展现更加效果,视频源是技术活,尤其作为直播背景

随着科技的飞速发展&#xff0c;视频制作和显示技术也在不断进步。透明拼接屏视频作为一种新型的视频形式&#xff0c;在许多场合都得到了广泛的应用。尼伽小编将深入探讨透明拼接屏视频的制作过程、要求、清晰度&#xff0c;以及目前常作为直播背景的优势。 一、透明拼接屏视频…

Apipost自动化测试+Jenkins实现持续集成

Apipost 自动化测试支持「持续集成」功能&#xff0c;在安装了Apipost的服务器中输入命令&#xff0c;即可运行测试脚本。 创建自动化测试脚本 在创建好的测试用例中选择「持续集成」。 点击新建&#xff0c;配置运行环境、循环次数、间隔停顿后点击保存会生成命令。 安装 Ap…

Git搭建

文件格式 <VirtuaHost * 80> nginx </virtualHost> pache xml server {} nginx conf格式 [xx] 配置内容 代码开发中版本控制,项目代码编译构建,项目版本迭代全流程 命令300条 Hospital Information System 开发语言分类: 编译型: C nginx ma…

C语言零基础入门第2天《 visual studio下载安装教程和搭建开发环境及踩坑指南》(保姆级图文教程)

visual studio下载安装教程和搭建开发环境 1、 项目实战效果图2、简单了解一下目前主流的开发环境3、 visual studio下载地址4、 visual studio安装教程5、 配置visual studio环境变量 6、如何新建一个C项目7、新建第一个C程序8、用代码测试创建的项目是否可用8、如何成功让代码…

spire.doc合并word文档

文章目录 spire.doc合并word文档1. 引入maven依赖2. 需要合并的word3. 合并文档代码4. 合并结果 spire.doc合并word文档 1. 引入maven依赖 <repositories><repository><id>com.e-iceblue</id><name>e-iceblue</name><url>https://r…

蓝桥杯(Python)每日练Day5

题目 OJ1229 题目分析 题目完全符合栈的特征&#xff0c;后进先出。如果能够熟练使用列表的9种方法那么这道题很容易解出。 题解 a[]#存衣服 nint(input()) for i in range(n):llist(input().split())#判断每一步的操作if len(l[0])2:a.append(l[1])else:while a.pop()!l…

蓝桥杯备战——1.点亮LED灯

1.解析原理图 由上图可以看到8个共阳LED灯接到了573输出口&#xff0c;而573输入接到单片机P0口上。当573 LE脚输入高电平时&#xff0c;输出随输入变化&#xff0c;当LE为低电平时&#xff0c;输出锁存。 由上图可以看到Y4C接到了或非门74HC02的输出端&#xff0c;而输入端为…

rabbitmq基础-java-4、Direct交换机

1、简介 在Fanout模式中&#xff0c;一条消息&#xff0c;会被所有订阅的队列都消费。但是&#xff0c;在某些场景下&#xff0c;我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。 2、特点 在Direct模型下&#xff1a; 队列与交换机的绑定&#xff0c;…

【RT-DETR有效改进】交叉形窗口网络 | CSWinTransformer(附代码 + 修改教程)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

【Web前端开发基础】CSS3之Web字体、字体图标、平面转换、渐变

CSS3之Web字体、字体图标、平面转换、渐变 目录 CSS3之Web字体、字体图标、平面转换、渐变一、Web字体1.1 Web字体概述1.2 字体文件1.3 font-face 规则 二、字体图标2.1 字体图标2.2 字体图标的优点2.3 图标库2.4 下载字体包2.5 字体图标的使用步骤2.6 字体图标使用注意点2.7 上…

Hive常见问题汇总

Hive和Hadoop的关系 Hive 构建在 Hadoop 之上&#xff0c; HQL 中对查询语句的解释、优化、生成查询计划是由 Hive 完成的 所有的数据都是存储在 Hadoop 中 查询计划被转化为 MapReduce 任务&#xff0c;在 Hadoop 中执行&#xff08;有些查询没有 MR 任务&#xff0c;如&…

【开源】基于JAVA的假日旅社管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统介绍2.2 QA 问答 三、系统展示四、核心代码4.1 查询民宿4.2 新增民宿评论4.3 查询民宿新闻4.4 新建民宿预订单4.5 查询我的民宿预订单 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的假日旅社…

IDEA插件Apipost-Helper如何使用

Apipost-Helper是由Apipost推出的IDEA插件&#xff0c;写完接口可以进行快速调试&#xff0c;且支持搜索接口、根据method跳转接口&#xff0c;还支持生成标准的API文档&#xff0c;注意&#xff1a;这些操作都可以在代码编辑器内独立完成&#xff0c;非常好用&#xff01;这里…