Vue3组件间的通信方式

这篇具有很好参考价值的文章主要介绍了Vue3组件间的通信方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

 1.props父向子组件通信

2.自定义事件 子向父组件通信

3.全局事件总线

4.v-model组件通信(父子组件数据同步)

绑定单个数据同步 

绑定多个数据同步 

5.useAttrs组件通信

 6.ref与$parent

ref获取子组件实例对象

 $parent获取父组件实例对象

 7.provide-inject 可以实现隔辈传输

8.Pinia

选择式API:

组合式API:


我们用Vue3开发项目时,常常需要面对的一个问题就是组件之间的通信,如何将数据发给对应的组件,这是不可避免的一个问题,该篇讲述了Vue3的8大主要通信方式。(还有其他的可以补充)

 1.props父向子组件通信

父组件:

props用于父组件向子组件传递数据,子组件用defineProps接收父组件传递来的参数

在父组件中我们可以在使用子组件时,对其传递props数据

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

其中没有使用v-bind的数据为固定数据,如果使用v-bind即是动态的数据

子组件:

在子组件中接收数据

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

这种方式是简单写法,还有一种对象写法,用法更加的多,可以规定数据类型和默认值/

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

在子组件中使用也是很简单(这二种方式都可以)

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

注意点:props的数据为只读数据,不可以进行修改

2.自定义事件 子向父组件通信

父组件

父组件中接收自定义事件

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

子组件

主要是子组件利用defineEmits方法返回函数触发自定义事件

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

绑定事件传递参数

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

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

点击按钮时会传递数据到父组件,父组件会接收到对应的参数

3.全局事件总线

由于在Vue3中,其vue构造函数被移除,导致其没有了VM,无法做到$bus全局事件总线,要想实现全局事件总线可以使用mitt插件来实现

可以在项目中安装mitt

npm install --save mitt

在需要传递数据的组件中 $bus.emit方法是传递数据

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

 在接收数据的组件中,$bus.on即是接收数据的方法

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

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

4.v-model组件通信(父子组件数据同步)

大家对v-model的印象可能只是觉得它可以用来实现表单数据的双向绑定,但其实它还可以用来实现父子组件数据同步

绑定单个数据同步 

如果我们不使用v-model,要想让父子组件的数据同步,许哟同时用到props和自定义事件才可以实现,像下面这样:

父组件:

//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>

子组件:

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

可以看到我们需要同时用到了props和自定义事件可以实现父子组件的数据同步

使用v-model是实现:

只需要修改子组件的标签就行

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

       v-model在组件身上使用

       1:相当有给子组件传递props[modelValue] = 10000

       2:相当于给子组件绑定自定义事件update:modelValue

绑定多个数据同步 

父组件:

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

子组件接收:

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

其主要实现原理还是利用了props和自定义事件的组合使用,v-model只是帮我们同步了数据和方法

5.useAttrs组件通信

父组件:将message属性传递给子组件

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

子组件:用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可以接收到父组件的属性Vue3组件间的通信方式,vue,前端,vue.js,前端,typescript

这样就实现了子组件接收父组件的数据

Vue3组件间的通信方式,vue,前端,vue.js,前端,typescript

useAttrs的功能于props的功能很类似,都是父组件传递数据给子组件,如果使用了props和useAttrs同时接收数据,props的优先级比useAttrs高

 6.ref与$parent

ref获取子组件实例对象

ref:可以获取真实的DOM节点,可以获取到子组件实例VC,在父组件中拿到子组件的实例,那么就可以操作子组件的属性及方法了,默认情况下是不能拿到的,子组件需要对外暴露才行

父组件:

<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()
}
})

 子组件:

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

子组件的实例对象:Vue3组件间的通信方式,vue,前端,vue.js,前端,typescript 

 $parent获取父组件实例对象

$parent:可以在子组件内部获取到父组件的实例

父组件只要放子组件即可:

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

在子组件中用$parent获取到父组件的实例对象,当然我们的父组件也需要对外暴露才能让子组件拿到实例对象

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

利用点击事件注入$parent拿到父亲的实例对象Vue3组件间的通信方式,vue,前端,vue.js,前端,typescript

 7.provide-inject 可以实现隔辈传输

父组件:用provide传输对应的数据,并提供一个key,后续的子组件在拿数据也是根据此key

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

子组件:使用inject和对应的key获取到对应的数据

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

孙组件:数据可以进行修改,而且所有的组件数据都是同步的

<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.Pinia

相比于 Vuex,Pinia 提供了更简洁直接的 API,并提供了组合式风格的 API,最重要的是,在使用 TypeScript 时它提供了更完善的类型推导。

这也是vue官方更加推荐的状态集中管理工具的原因

Vue3组件间的通信方式,vue,前端,vue.js,前端,typescript

 在使用pinia时需要安装其依赖

npm i pinia

 pinia可以支持vue2和vue3,所以有二种写法,组合式和选择式

1.新建仓库文件store创建index.ts大仓库

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

2.在mian.js中引用

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

选择式API:

state存放数据

actions实现方法(可以之间修改数据)

getters计算属性

//定义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;

在组件中使用pinia数据

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

组合式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;

在组件中使用:文章来源地址https://www.toymoban.com/news/detail-581101.html

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

到了这里,关于Vue3组件间的通信方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Vue3.2+TS的组件间的v-model传值

    组件之间的v-model,为什么可以v-model,大家可以去看看v-model的原理,然后就会发现这个方法一目了然。 父组件 子组件 假如子组件需要按照某个方法变化,那么可以自己定义,比如需要自增加50

    2024年02月13日
    浏览(15)
  • 前端vue3+typescript架构

    前端vue3+typescript架构

    1、vue creat 项目名称 选择自定义  选择需要的依赖  选择vue3  一路enter,选择eslist+prettier  继续enter,等待安装 按步骤操作,项目启动成功  2、vscode安装5款插件  2、代码保存自动格式化,保证每个开发人员代码一致,根目录新建三个文件.editorconfig和.prettierrc和.prettierignore

    2024年02月11日
    浏览(15)
  • vue3项目+TypeScript前端项目—— vue3搭建项目+eslint+husky

    vue3项目+TypeScript前端项目—— vue3搭建项目+eslint+husky

    今天来带大家从0开始搭建一个vue3版本的后台管理系统。一个项目要有统一的规范,需要使用eslint+stylelint+prettier来对我们的代码质量做检测和修复,需要使用husky来做commit拦截,需要使用commitlint来统一提交规范,需要使用preinstall来统一包管理工具。 下面我们就用这一套规范

    2024年02月22日
    浏览(13)
  • 《Vue3+Typescript》一个简单的日历组件实现

    《Vue3+Typescript》一个简单的日历组件实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~ 主页: oliver尹的主页 格言: 跌倒了爬起来就好~ 目录 一、前言 二、效果图 三、核心思路 四、代码实现 4.1 本月日期

    2024年02月14日
    浏览(8)
  • Vue3,Typescript中引用组件路径无法找到模块报错

    Vue3,Typescript中引用组件路径无法找到模块报错

    是这么个事,我在vue3新创建的项目里,写了个组件叫headerIndex.vue,放到app.vue中import就会报错 路径肯定没写错,找到了解决方法,但是也没想明白为什么 解决方法如下 在vite-env.d.ts文件中加入 就好了,大概意思就是在文件中把组件声明一下,but why

    2024年02月09日
    浏览(10)
  • VUE3 组件通信

    VUE3 组件通信

    用途:可以实现父子组件、子父组件、甚至兄弟组件通信 父组件 子组件 用途:可以实现子父组件通信 父组件 子组件 用途:可以实现任意组件通信 安装  配置 新建bus.js文件 使用 父组件 子组件 父组件 子组件 父组件 子组件 父组件 子组件 父组件 儿子组件1 儿子组件2 安装

    2024年03月19日
    浏览(16)
  • vue3.0组件通信

    没有加TS限制类型的时候 注意: defineProps()会返回一个对象,这个对象可以直接.出数据 加TS写法 规则: 非函数类型 基本数据类型 - 展示 引用数据类型 - 展示,但是可以修改属性,不推荐(违反单向数据流 - 不是绝对禁止使用的,偷懒可以用) 函数类型 - 子组件调用父组件传过来的函数

    2024年02月12日
    浏览(16)
  • vue3组件通信详解

    vue3组件通信详解

    vue3组件通信方式有以下几种:porps,$emit, bus,v-model, useAttrs ,$ref/$parent,provide/inject,pinia,slot。下面将逐一讲解。    目录 1.porps:实现父子组件通信,子组件接收的数据还是只读  2.$emit 3.全局事件总线 $bus,使用mitt 4.v-model传值 5. $attrs/useAttrs:获取组件标签身上属性与

    2024年02月07日
    浏览(11)
  • 用Typescript 的方式封装Vue3的表单绑定,支持防抖等功能。

    Vue3 的父子组件传值、绑定表单数据、UI库的二次封装、防抖等,想来大家都很熟悉了,本篇介绍一种使用 Typescript 的方式进行统一的封装的方法。 Vue3对于表单的绑定提供了一种简单的方式: v-model 。对于使用者来说非常方便, v- model=\\\"name\\\" 就可以了。 但是当我们要自己做一

    2024年02月06日
    浏览(12)
  • Vue3 组件之间的通信

    Vue3 组件之间的通信

    经过前面几章的阅读,相信开发者已经可以搭建一个基础的 Vue 3 项目了! 但实际业务开发过程中,还会遇到一些组件之间的通信问题,父子组件通信、兄弟组件通信、爷孙组件通信,还有一些全局通信的场景。 这一章就按使用场景来划分对应的章节吧,在什么场景下遇到问

    2023年04月08日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包