Vue3 组件之间的通信

一、父子通信

① props 父传子(这种传值方法是只读的,不可以进行修改

父组件props.vue中

<template>
  <h2>props:我是父组件</h2>
  <hr>
  <props-child msg="我是静态的数据" :num="num" :obj="{ name:'小黑',age:18 }">
  </props-child>
</template>
 
<script setup lang="ts"> 
import { ref } from 'vue'
// props:可以实现父子组件的通讯,props数据还是只读的(不能修改!!)
import propsChild from './propsChild.vue';
let num = ref(521)
</script>

子组件 propsChild.vue 中接收数据

<template>
  <h2>propsChild:我是子组件</h2>
  <!-- 在模板使用时,可以直接省略前面的props(两种方式都可以) -->
  <div>{{msg}}----{{num}}</div>
  <div>{{props.msg}}----{{props.num}}</div>
  <div>{{ obj.name }}---{{ obj.age }}</div>
</template>
 
<script setup lang="ts"> 
// v3使用的是defineProps方法接收父组件传递过来的数据(不需要引入直接使用)
 
// const props = defineProps(['msg','num']) //  1、 可以写数组也可以写对象
/** 第二种写法,有默认类型和默认参数。
const props = defineProps({
  msg:{
   type:String,//接受的数据类型
   default:'默认参数',//接受默认数据
  },
  num:{
   type:Number,
   default:0
   }
})
*/
interface Iprops {
  name:string,
  age:number
}
const props = defineProps<{
  msg:String,
  num:Number,
  obj:Iprops
}>()
</script>

② 子给父传 (自定义事件 使用defineEmits(['xxx'])

eventChild.vue 子组件通过一个事件去触发传值

  <template>
     <div>eventChild</div>
     <button @click="handleClick">子组件按钮</button>
  </template>
  
  <script setup lang="ts">
  // 利用defineEmits方法返回函数触发自定义事件(不需要引入直接用)
  // 未用 Ts 写法   
  // const emit = defineEmits(["event"])
  // const handleClick = () => {
  //     emit('event','小黑')
  // }
 
    //用ts写法
    const emit = defineEmits<{
        (e:'event',myvalue:string):void
    }>()
    const handleClick = () => {
        emit('event','小黑'); //提交第一个参数是事件名 ,后面都是携带的参数
    }
  </script>

eventFather.vue 父组件通过自定义事件接收

<template>
    <h2>event1</h2>
   <EventChild @event="eventFn"></EventChild>
</template>
 
<script setup lang="ts">
import EventChild from './eventChild.vue'
 
const eventFn = (val) => {
    console.log(val);
}
</script>

二、兄弟通信(全局事件总线)

需要借助插件 mitt

npm install --save mitt

① 引入(新建bus文件夹创建index.ts)

 暴漏出方法 

// 引入mitt :注意mitt是一个方法,执行后会返回bus对象
import mitt from "mitt";
const bus = mitt()
export default bus

 ② 兄弟之间传值eventBus1和eventBus2

③ 父级eventBus使用两兄弟

<template>
  <h2>eventBus全局总线</h2>
  <EventBus1></EventBus1>
  <EventBus2></EventBus2>
</template>
 
<script setup lang="ts">
import EventBus1 from './eventBus1.vue'
import EventBus2 from './eventBus2.vue'
</script>

  ④  eventBus2 传值给 eventBus1

<template>
  <h3>eventBus2</h3>
  <button @click="handler">点击给eventBus1传值</button>
</template>
 
<script setup lang="ts">
import bus from '../../bus'
const handler = () => {   //emit(送东西)
  bus.emit('msg', { name: '小黑'})
}
</script>

⑤ eventBus1接收

<template>
  <h3>eventBus1</h3>
</template>
 
<script setup lang="ts">
import bus from '../../bus/'
import { onMounted } from 'vue';
onMounted(()=> {
  // 第一个参数:为事件的类型,第二个参数为事件的回调
  bus.on('msg',(val)=> {   //on(收东西!!)
    console.log('val',val);
  })
})
</script>

三 、v-model (父子组件数据同步)

v-model指令:手机表单数据,数据双向绑定 v-model也可以实现组件之间通信,实现父子组件数据同步业务。 这个v-model就是把defineProps和defineEmits 结合起来 使用父传子到子传父形成数据同步 可以同时绑定多个v-mdoel。

1、写一个

① 父组件 vModel.vue

<template>
  <h4>v-model(父组件)---{{num}}</h4>
  <vModelSon1 v-model="num"></vModelSon1> 
 
   <!--  v-model相当于下面这个写法 相当于简化了--> 
  <vModelSon1 :modelValue="num" @update:modelValue="handler"></vModelSon1> 
</template>
 
<script setup lang="ts">
import { ref } from 'vue';
import vModelSon1 from './vModelSon1.vue'
 
let num = ref(100)
const handler = (sonNum) => {
    // 接收子组件传的数据
    num.value = sonNum
}
</script>

② 子组件vModelSon1.vue

<template>
  <div style="background:#ccc">
    <div><h4>vModelSon1(子组件)</h4></div>
    <div>{{ modelValue }} ----接收父组件的值 </div>
    <button @click="sonClick">子组件按钮</button>
  </div>
</template>
 
<script setup lang="ts">
  let props = defineProps(['modelValue'])
  let emit = defineEmits(['update:modelValue'])
  const sonClick = () => {
    emit('update:modelValue',props.modelValue+2)
  }
</script>

 2、写多个

① 父组件 vModel.vue

<template>
  <h4>v-model(父组件)---num: {{num}}--num1: {{ num1 }}</h4>
  <!-- 就相当于传了两个props 而且相当于给子组件绑了两个自定义事件update:num和update:num1 -->
  <vModelSon2 v-model:num="num" v-model:num1="num1"></vModelSon2> 
</template>
 
<script setup lang="ts">
  import { ref } from 'vue';
  import vModelSon2 from './vModelSon2.vue'
 
  let num = ref(100)
  let num1 = ref(200)
</script>

② 子组件vModelSon2.vue

<template>
  <h4>vModelSon2(同时绑定多个v-model)</h4>
  <button @click="numClick">{{ num }}</button>
  <button @click="num1Click">{{ num1 }}</button>
</template>
 
<script setup lang="ts">
let props = defineProps(['num','num1'])
let emit = defineEmits(['update:num','update:num1'])
const numClick = () => {
  emit('update:num',props.num+2)
}
const num1Click = () => {
  emit('update:num1',props.num1+4)
}
</script>

即可完成父子组件数据同步

四、useAttrs

 vue3框架提供了一个方法useAttrs方法,可以获取到组件身上的属性和事件

和props一样 二者之中props如果声明了接收的值,那么useAttrs就接收不到了、 父组件中间照常写给子组件传值的代码

① 父组件attrs.vue

<template>
  <h3>父组件attrs</h3>
  <attrsSon type="primary"  title="名字" @event="handleEvent" @xxx="handle"></attrsSon>
</template>
 
<script setup lang="ts"> 
import attrsSon from './attrsSon.vue';
const handleEvent = () => {}
const handle = () => {}
</script>

 ② 子组件attrsSon.vue

<template>
  <div>
    子组件:{{ attrs.title }}
  </div>
</template>
 
<script setup lang="ts">
// 引入useAttrs方法:获取组件(attrsSon)身上的属性和事件
import { useAttrs } from 'vue';
// 此方法会返回一个对象
let attrs = useAttrs()
console.log('attrs',attrs);
 
// 注:useAttrs和defineProps同时存在则defineProps优先级高
</script>

五、ref 和 $parent (父子通信) 加上defineExpose对外暴露来拿到数据进行修改

① 通过 ref ( 父组件可以拿到子组件的属性和方法 )

 父组件refather.vue

<template>
  <div style="color:#0ee993">
     父组件的数量:{{ num }}
  </div>
  <button @click="fatherBtn">父按钮</button>
  <refParentSon ref="sonRef"></refParentSon>
</template>
 
<script setup lang="ts">
import refParentSon from './ref-parent-son.vue'
import {ref, getCurrentInstance} from 'vue'
/** 
// 获取子组件的实例
const { proxy } = getCurrentInstance();   
proxy.$refs.sonRef
*/
let num = ref(100)

// 获取子组件的实例
let sonRef = ref()
const fatherBtn =() => {
    num.value+=2
    sonRef.value.num-=2  //子组件的属性
    sonRef.value.fn()  //子组件的方法
}
</script>

子组件refParentSon.vue

<template>
  <div style="color:#000993">
    子组件的数量:{{ num }}
  </div>
</template>
 
<script setup lang="ts">
import {ref} from 'vue'
let num = ref(10)
const fn = () =>{ console.log('我是子组件的方法')}

// 组件内部的数据对外关闭,如若想对外使用需通过defineExpose方法暴露
defineExpose({
  num,fn
})
</script>

① 通过$parent ( 可以在子组件内部获取到父组件的实例 )

父组件refather.vue

<template>
  <div style="color:#0ee993">
     父组件的数量:{{ num }}
  </div>
  <refParentSon1></refParentSon1>
</template>
 
<script setup lang="ts">
import refParentSon1 from './ref-parent-son1.vue'
import {ref} from 'vue'
let num = ref(100)  //父组件的数据
const fatherFn = () => {console.log('父组件的方法')}

//父组件暴露数据
defineExpose({
    num,fatherFn
})
 
</script>

子组件ref-parent-son1.vue

<template>
  <div style="color: green">
    子组件的数量:{{ num }}
  </div>
  <button @click="sonClick($parent)">子按钮</button>
</template>
 
<script setup lang="ts">
// 子组件内部拿父组件的数据
import {ref} from 'vue'
let num = ref(10)
const sonClick = ($parent) => {
  num.value+=2
  $parent.num-=2  //子组件拿父组件数据
  $parent.fatherFn() //子组件拿父组件方法
}
</script>

六、provide 和 inject

vue3提供provide(提供)与inject(注入)可以实现隔辈组件传递数据  

父有子组件、子有孙组件(父组件数据儿可以用,孙也可以用)

  ① 父组件(祖先组件)provideAndInject.vue 中

<template>
    <div style="background-color:pink">
        父组件: <provideAndInjectSon></provideAndInjectSon>
    </div>
</template>
<script setup lang="ts">
  import provideAndInjectSon from './provideAndInjectSon.vue'
//vue3提供provide(提供)与inject(注入)可以实现隔辈组件传递数据   
  import {ref,provide} from 'vue'
  let msg = ref('我是祖先数据')

// 第一个参数是提供的数据key 第二个参数是提供的数据 
  provide("Tian",msg)
</script>

② 儿组件 provideAndInjectGrandson.vue 中

<template>
    <div style="border:1px solid red">
        我是儿子用父的数据---{{msg}}
        <provideAndInjectGrandson></provideAndInjectGrandson>
    </div>
</template>
  
<script setup lang="ts">
  import {inject} from 'vue'
  import provideAndInjectGrandson from './provideAndInjectGrandson.vue'

 //需要的参数:即为祖先提供的key
  let msg = inject('Tian')
  console.log('msg',msg);
</script>

③ 孙组件 provideAndInjectGrandson.vue 中

<template>
    <div style="background:green">
        我是孙子用父的数据---{{msg}}
    </div>
</template>
  
<script setup lang="ts">

  import {inject} from 'vue'
  let msg = inject('Tian')
  console.log('msg',msg);
</script>

七、任意组件之间的通信 pinia

① 安装:

npm install pinia

 ② 创建文件夹

③ index.ts

import { createPinia } from 'pinia'
// createPinia方法可以用于创建大仓库
let store = createPinia()
export default store

  ④ main.ts 

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
 
import store from './store'
 
const app = createApp(App)
 
app.use(store)
app.use(router)
app.mount('#app')

⑤ 在modules文件下创建一个小仓库info.ts

import { defineStore } from "pinia";
 
// defineStore方法接收两个参数
// 第一个参数接收:仓库的名字
// 第二个参数:仓库的配置对象
// 返回一个函数作用就是让组件可以获取到仓库的数据
let useInfoStore = defineStore('info', {
    // 存储数据:state
    state: () => {
        return {
            num:10,
            arr:[1,2,3]
        }
    },
    actions: {
        updateNum(val){
            // this就是仓库的数据对象
            this.num+=val
        }
    },
    getters: {
        // 计算一下arr数组的和
        total() {
            let ress = this.arr.reduce((pre,nex)=> {
                return pre+nex
            },0)
            return ress
        }
    }
})
 
 
// 对外暴露出去
export default useInfoStore

⑥ 在页面使用

<template>
  <div>
    pinia--{{ infoStore.num }}---总和:{{ infoStore.total }}
    <button @click="addNum">修改仓库数据</button>
  </div>
</template>
 
<script setup lang="ts">
import useInfoStore from '../../store/modules/info'
// 获取小仓库对象
let infoStore = useInfoStore()
console.log('infoStore',infoStore);
 
const addNum = () => {
    // 仓库调用自身的方法修改仓库的数据(也可以传参数)
    infoStore.updateNum(6);
}
</script>

    以上为pinia选择式API的写法
---------------------------------------------------------------------------------------------------------
   以下为pinia组合式API 的写法

① 新建一个仓库zuhe.ts 

import { defineStore } from "pinia";
import {ref,computed} from 'vue'
let useZuheStore = defineStore('zuhe', () => {
    // 箭头函数返回一个对象:属性与方法可以提供给组件使用
    let data = ref([
        {id:1, name:'小黑子'},
        {id:2, name:'背带裤'},
    ])
    let arr =ref([1,2,3])
    const total = computed(() => {
       return arr.value.reduce((pre,nex)=> {
            return pre+nex
        },0)
    })
    const upData = () => {
        data.value.push({ id:3, name:'梳中分'})
    }
    return {
        data,
        arr,
        upData,
        total
    }
})
 
 
// 对外暴露出去
export default useZuheStore

 ② 页面使用

<template>
    <div>
      页面使用:{{ zuheStore.data }} ---总和:{{zuheStore.total}}
    </div>
    <button @click="updateData">修改仓库数据</button>
</template>
  
<script setup lang="ts">
  import useZuheStore from '../../store/modules/zuhe'
  let zuheStore = useZuheStore()
 
  const updateData = () => {
    zuheStore.upData()
  }
</script>

八、插槽 

分为三种插槽:默认插槽,具名插槽,作用域插槽

① 默认插槽

父组件slotDemo.vue

<template>
  <div>父级</div>
  <slotDemoSon>
    <h3>小黑子</h3>
  </slotDemoSon>
</template>
 
<script setup lang="ts">
import slotDemoSon from './slotDemoSon.vue';
 
</script>

子组件slotDemoSon.vue

<template>
  <div>Son--默认插槽</div>
  <slot></slot>
</template>
 
<script setup lang="ts">
 
</script>

② 具名插槽

父组件slotDemo.vue

<template>
  <div>父级</div>
  <slotDemoSon>
    <!-- 具名插槽 -->
    <template v-slot:xiao>
        <div>我是填充具名插槽xiao位置结构</div>
    </template>
    <template #hei>  <!--v-slot 可以简写为#号-->>
        <div>我是填充具名插槽hei位置结构</div>
    </template>
  </slotDemoSon>
</template>
 
<script setup lang="ts">
import slotDemoSon from './slotDemoSon.vue';
 
</script>

子组件slotDemoSon.vue

<template>
  <div>Son--具名插槽</div>
  <slot name="xiao"></slot>
  <slot name="hei"></slot>
</template>

③ 作用域插槽

可以传递数据的插槽。子组件可以将数据回传给父组件,父组件可以决定这些回传数据是以何种结构或者外观(样式)在子组件内部去展示

父组件slotDemo.vue

<template>
    <div>父级</div>
    <slotDemoSon :arrList="arrList">
    <template v-slot="{data,index}"> <!--回传过来是对象所以可以解构-->
        <p>
            {{ data.name }}--{{index}}
        </p>
    </template>
  </slotDemoSon>
</template>
<script setup lang="ts">
import slotDemoSon from './slotDemoSon.vue';
import { ref } from 'vue'
 
let arrList = ref([
    { id:1, name:'小黑', type:false},
    { id:2, name:'小白', type:true},
    { id:3, name:'小蓝', type:false},
])
</script>

子组件slotDemoSon.vue

<template>
  <div>作用域插槽</div>
  <ul>
    <li v-for="(item,index) in arrList" :key="item.id">
      <!-- 作用域插槽:可以将数据回传给父组件 -->
      <slot :data="item" :index="index"></slot>
    </li>
  </ul>
</template>
 
<script setup lang="ts">
defineProps(['arrList'])
</script>

父组件可以决定这些回传数据是以何种结构或者外观在子组件内部去展示

上面父组件用了p标签进行展示

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

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

相关文章

VTK9.2.0+Qt5.14.0 绘制点云

背景 为了显示结构光重建后的点云&#xff0c;开发QT5.14.0VTK9.2.0的上位机软件&#xff0c;用于对结构光3D相机进行控制&#xff0c;并接收传输回来的3D数据&#xff0c;显示在窗口中。 配置QT和VTK VTK9.2.0下载源码&#xff0c;用Cmake编译&#xff0c;编译好的VTK9.2.0…

GitHub gpg体验

文档 实践 生成新 GPG 密钥 gpg --full-generate-key查看本地GPG列表 gpg --list-keys关联GPG公钥与Github账户 gpg --armor --export {key_id}GPG私钥对Git commit进行签名 git config --local user.signingkey {key_id} # git config --global user.signingkey {key_id} git…

30V转5V 1A 30降压12V 1A DCDC低电压恒压IC 车充芯片-H4110

30V转5V和30V转12V的DCDC低电压恒压IC&#xff08;也称为降压恒压芯片或车充芯片&#xff09;工作原理如下&#xff1a; 输入电压识别&#xff1a;芯片首先识别输入的30V电压&#xff0c;并准备进行转换。 PWM控制&#xff1a;芯片内部的控制逻辑生成PWM信号。这个信号用于控制…

JVM—内存可见性

什么是可见性 可见性&#xff1a;一个线程对共享变量值的修改,能够及时地被其他线程看到共享变量&#xff1a;如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JMM) Java内存模型(Java Memory Model)描述了Java程序中各种…

Qt教程 — 3.7 深入了解Qt 控件: Layouts部件

目录 2 如何使用Layouts部件 2.1 QBoxLayout组件-垂直或水平布局 2.2 QGridLayout组件-网格布局 2.3 QFormLayout组件-表单布局 在Qt中&#xff0c;布局管理器&#xff08;Layouts&#xff09;是用来管理窗口中控件位置和大小的重要工具。布局管理器可以确保窗口中的控件在…

BAAI 北京智源研究院

文章目录 关于 BAAI产品悟道大模型FlagOpen 大模型技术天演 生物智能九鼎 智算平台 关于 BAAI BAAI : Beijing Academy of Artificial Intelligence 北京智源研究院 官网&#xff1a;https://www.baai.ac.cnhf : https://huggingface.co/BAAI百度百科 https://baike.baidu.co…

物联网云组态是什么?部署物联网云组态有什么作用?

在信息化与工业化的深度融合进程中&#xff0c;物联网云组态以其独特的优势&#xff0c;正在成为企业数字化转型的重要工具。那么&#xff0c;物联网云组态究竟是什么呢&#xff1f;部署物联网云组态又能给企业带来哪些实质性的好处呢&#xff1f;今天&#xff0c;我们将围绕这…

2核4G服务器多少钱?阿里云价格30元起

阿里云2核4G服务器租用优惠价格&#xff0c;轻量2核4G服务器165元一年、u1服务器2核4G5M带宽199元一年、云服务器e实例30元3个月&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接如下图&#xff1a; 阿里云2核4G服务器优惠价格 轻量应用服务器2核2G4M带宽、60GB高效…

AI智能分析网关V4在养老院视频智能监控场景中的应用

随着科技的快速发展&#xff0c;智能监控技术已经广泛应用于各个领域&#xff0c;尤其在养老院这一特定场景中&#xff0c;智能监控方案更是发挥着不可或缺的作用。尤其是伴随着社会老龄化趋势的加剧&#xff0c;养老院的安全管理问题也日益凸显。为了确保老人的生活安全&#…

Ruby选择结构实战

文章目录 一、Ruby选择结构实战概述二、Ruby选择结构实战案例&#xff08;一&#xff09;闰年判断1、编写程序&#xff0c;实现功能2、程序的解释说明3、运行程序&#xff0c;查看结果 &#xff08;二&#xff09;求解一元二次方程1、编写程序&#xff0c;实现功能2、程序的解释…

界面控件DevExpress ASP.NET Ribbon组件 - 完美复刻Office 365体验!

无论用户是喜欢传统工具栏菜单外观、样式&#xff0c;还是想在下一个项目中复制Office 365 web UI&#xff0c;DevExpress ASP.NET都提供了所需要的工具&#xff0c;帮助用户打造更好的应用程序界面。 P.S&#xff1a;DevExpress ASP.NET Web Forms Controls拥有针对Web表单&a…

ky10.aarch64安装Jenkins

参考地址&#xff1a;《安装部署 Jenkins》 前言 有war包和rpm两种安装方式&#xff0c;如果是长期使用更加推荐rpm的安装方式&#xff0c;可以更好的管理Jenkins&#xff1b; 我此次安装jenkins主要用于测试和简单的个人使用&#xff0c;所以选择更轻便的war安装。 1 下载J…

如何用java使用es

添加依赖 如何连接es客户端 RestHighLevelClient 代表是高级客户端 其中hostname&#xff1a;es的服务器地址&#xff0c;prot端口号 &#xff0c;scheme&#xff1a;http还是https 如果不在使用es可以进行关闭&#xff0c;可以防止浪费一些资源 java如何创建索引&#xff1…

Python RPA简单开发实践(selenium登陆浏览器自动输入密码登陆)

打开csdn博客&#xff0c;简单版 class BS:def __init__(self, url):self.url url# self.password password# self.username usernamedef login_url(self):from selenium import webdriver# 不自动关闭浏览器option webdriver.ChromeOptions()option.add_experimental_opt…

每日OJ题_牛客_QQ2 微信红包

目录 牛客_QQ2 微信红包 解析代码 牛客_QQ2 微信红包 微信红包_牛客题霸_牛客网 解析代码 class Gift { public: int getValue(vector<int> gifts, int n) {int cnt 0, ret 0;// for(int i 0; i < n; i) // 摩尔投票法// {// if(cnt 0)// {// ret gifts[i];/…

STM32不使用中断实现定时器微秒级精确延时

我们在写代码的时候避免不了要使用延时函数&#xff0c;很多延时函数都是使用中断或者tick来实现的&#xff0c;tick的方式最大到毫秒ms级别&#xff0c;通过中断方式的通用定时器来实现&#xff0c;如果实现1us的延时那么每1us就来一次中断&#xff0c;很影响cpu的效率。 本文…

【webpack】----错误解决【Cannot read properties of undefined (reading ‘tap‘)】

1. 报错场景 安装 webpack-obfuscator 后&#xff0c;进行 js 代码混淆编译的时候报错。 2. 报错截图 3. 错误原因 通常是由于版本不兼容或配置错误引起的。 4. 查询本地 webpack 版本 4.1 查询命令 npm 查询 npm view webpack versionyarn 查询 yarn info webpack ver…

C++ —— 日期计算器

1. 头文件 #pragma once #include <iostream> using namespace std;class Date { public:Date(int year 1, int month 1, int day 1);int GetMonthDay();bool operator>(const Date& d) const;bool operator>(const Date& d)const;bool operator<(c…

opencv函数使用查找

opencv官方文档地址&#xff1a;https://docs.opencv.org/4.x/index.html 先选对应的版本opencv-python 以这个函数为例子 model cv2.face.LBPHFaceRecognizer.create() 点开后找face类的LBP里面就有create函数的用法

vue 安装脚手架报错 certificate has expired

vue 安装脚手架的时候报错&#xff0c;报错信息如下&#xff1a; 错误信息&#xff1a;npm ERR! request to https://registry.npm.taobao.org/vue%2fcli failed, reason: certificate has expired 翻译&#xff1a;npm ERR&#xff01;请求到https://registry.npm.taobao.org…