vue3组件通信的方式

一、父传子 props 和子传父 $emit


1、父传子 props

在开发中最常见的就是父子组件之间通信,父组件往子组件通信使用的是props。子组件往父组件通信则使用的是 $emit

父组件代码:

使用 message=“从父组件传到子组件” 将数据传到about子组件中。

<template><about message="从父组件传到子组件"></about>
</template><script>
import about from './componets/about.vue'
export default {name: 'App',components:{about}
}
</script><style>
</style>
子组件接收数据:

使用props接收从父组件中传过来的数据

<template><h3>{{message}}</h3>
</template><script>
export default {name:'AppAbout',props:['message']}
</script><style></style>

除了使用数组接收之外还可以有一下几种方式:
1.使用对象接收的话可以为message设置类型

  props:{message:String}

2.将message 设置为数组的话可以设置匹配多个类型

  props:{message:[String,Number]}

3.除了可以设置类型之外还可以设置默认值和是否是必须传递的参数
default:默认值
require:是否是必传的值
当然了设置了默认值就没必要设置必传了

  props:{message:{type:String,default:"默认值",require:true}}

4.还可以自定义一些验证函数
验证 sex 是否是男或者女

  props:{sex:{validator(value){return ['男','女'].includes(value)}}}

5.注意数组或者对象的默认值必须是通过函数return出去的一个值
因为数组和对象都是属于复杂数据类型,为了保持使用组件的时候,多个组件不出现数据污染的情况必须使用函数return 出去一个对象或者数组。原理是使用函数return 出来的一个数组或者对象都在堆空间中拥有独立的空间都是互不干扰的。

  props:{nameArr:{type:Array,default(){return ["小红","小明","小李"]}}}

6.Prop 的大小写命名(camelCase vs kebab-case)HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名;

  <about :userName="user.name"></about><about :user-name="user.name"></about>

7.当从父组件中传递出来的数据在子组件中没有设置props接收的时候。Vue就会将属性传递到子组件的根元素中。常见的属性:class、style、id。
父组件内容:

<template><about id="about" class="about" style="background:red" fff="'ddd'"></about>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',components:{about}
}
</script>
<style>
</style>

子组件内容:

<template><span>about内容</span>
</template>
<script>
export default {name:'AppAbout',props:{}
}
</script>
<style>
</style>

浏览器样式:


由于子组件没有在props中接收id、class、style、fff,所有这些元素自动继承到了子元素的根元素中。

特殊情况:

1.如果不想根元素继承可以设置inheritAttrs:false
子组件:

<template><about>about内容</about>
</template>
<script>
export default {name:'AppAbout',props:{},inheritAttrs:false
}
</script>
<style>
</style>

浏览器样式:

2.当不想将父组件传递过来的数据继承到子组件的根元素的时候,可以通过 设置inheritAttrs:false禁止继承到根元素上。再通过 $attrs 获取到重父组件传递过来的数据。

浏览器样式:

3.当子组件中没有根元素的时候,他就不会继承了。当然控制台中会报警告,我们必须手动的指定要绑定到哪一个属性上。
子组件:

<template>about内容
</template>
<script>
export default {name:'AppAbout',props:{}
}
</script>
<style>
</style>

浏览器样式:

4.当拥有多个根元素的时候,也不会继承。同样的在控制台中会报警告。
子组件:

<template><div>about内容一</div><div>about内容二</div><div>about内容三</div>
</template>
<script>
export default {name:'AppAbout',props:{},inheritAttrs:false
}
</script>
<style>
</style>

浏览器样式:

2、子传父 $emit

通过再子组件中emits中注册自定义事件,然后在某个时间发射自定义事件 $emit。最后在父组件中监听到自定义事件,触发绑定的方法。
父组件:

<template><about @changEvent="chang">{{message}}</about><div>{{message}}</div>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',components:{about},data(){return {message:"空"}},methods:{chang(value){this.message = value;}}
}
</script>
<style>
</style>

子组件:

<template><button @click="send()">点击传递数据</button>
</template>
<script>
export default {name:'AppAbout',emits:{changEvent:null},methods:{send(){this.$emit("changEvent","传过去的value")}}
}
</script>
<style>
</style>

变化:

开始在父组件中展示的message:“空” 点击按钮触发子组件按钮点击事件。触发自定义事件changEvent。然后再触发父组件中的chang。接收到子组件中传送过来的参数。

注意在父组件监听事件的时候不需要写括号,写了括号会覆盖掉从子组件传过来的数据。

父组件:

<template><about @changEvent="chang">{{message}}</about>    <!-- 正确,value值为“传过去的value” --><about @changEvent="chang()">{{message}}</about>  <!-- 错误,value为undefined --><about @changEvent="chang(value)">{{message}}</about>  <!-- 错误,value为undefined --><div>{{message}}</div>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',components:{about},data(){return {message:"空"}},methods:{chang(value){console.log(value);this.message = value;}}
}
</script>
<style>
</style>

除了用数组注册事件,还可以用对象注册,同时可以对传递的参数进行验证。验证失败会在控制台弹出警告。
子组件:

<template><button @click="send()">点击传递数据</button>
</template>
<script>
export default {name:'AppAbout',emits:{changEvent:(value)=>{let type = typeof valueif(type =="string" ){return true //验证成功,正常执行}return false //验证失败,也正常执行。但是弹出警告。 },changEvent1:null, //没有验证},methods:{send(){this.$emit("changEvent","传过去的value")}}
}
</script>
<style>
</style>

二、非父子组件的通信Provide和Inject

开发中最常用的通信方式是父子通信,但是当有一些嵌套比较深的组件比如孙子组件想要获取他爷爷组件中的数据的时候,就需要通过props逐级传递下去,相对来说比较麻烦。
provide 和 inject 可以帮助我们解决这一问题。 一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
1.简单使用。
父组件:

<template><about></about>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',provide: {message: '你好!',},components:{about}
}
</script>
<style>
</style>

子组件:

<template><h2>about:{{message}}</h2>
</template>
<script>
export default {name:'AppAbout',inject:['message']
}
</script>
<style>
</style>

浏览器效果:

通过父组件中提供依赖Provide ,然后再子组件中注入Inject 。不只是父子组件,只要是提供依赖组件的后代组件都可以通过Inject注入。
2.当需要传递注入data里面的值的时候需要使用函数的形式就可以通过this访问到data里面的值。
父组件:

<template><about></about>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',provide(){return {message:this.message}},data(){return {message:"hello!"}},components:{about}
}
</script>
<style>
</style>

子组件不变!!
浏览器效果:

3.注入会在组件自身的状态之前被解析,因此你可以在 data() 中访问到注入的属性。
子组件:

<template><h2>about:{{mees}}</h2>
</template>
<script>
export default {name:'AppAbout',inject:['message'],data(){return {mees:this.message}}
}
</script>
<style>
</style>

父组件不变!!

浏览器效果:

3.当提供依赖的父组件起的名字和当前组件名字出现冲突的时候,可以通过起别名的方式避免冲突。
子组件:

<template><h2>about:{{localMessage}}</h2>
</template>
<script>
export default {name:'AppAbout',inject:{/* 本地属性名 */ localMessage: {from: /* 注入来源名 */ 'message'}},
}
</script>
<style>
</style>

父组件不变!!

浏览器效果:

4.默认情况下,inject 假设传入的注入名会被某个祖先链上的组件提供。如果该注入名的确没有任何组件提供,则会抛出一个运行时警告。如果在注入一个值时不要求必须有提供者,那么我们应该声明一个默认值。
父组件:

<template><about></about>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',provide(){return {// message:this.message}},data(){return {message:"hello!"}},components:{about}
}
</script>
<style>
</style>

子组件:

<template><h2>about:{{localMessage}}</h2>
</template>
<script>
export default {name:'AppAbout',inject:{localMessage: {from: 'message',default: "默认值"}},
}
</script>
<style>
</style>

浏览器样式:

5.请注意这不会使注入保持响应性。当父组件中message发生变化的时候。子组件中的message是不会改变的。
父组件:

<template><about></about><div>{{message}}</div><button @click="change()">按钮</button>
</template>
<script>
import about from './componets/about.vue'
export default {name: 'App',provide(){return {message:this.message}},data(){return {message:"hello!"}},components:{about},methods:{change(){this.message = "修改后的值"}}
}
</script>
<style>
</style>

子组件:

<template><h2>about:{{localMessage}}</h2>
</template>
<script>
export default {name:'AppAbout',inject:{localMessage: {from: 'message',default: "默认值"}},
}
</script>
<style>
</style>

浏览器效果:

当然这个问题是可以解决的。需要使用 computed() 函数提供一个计算属性。
父组件:

<template><about></about><div>{{message}}</div><button @click="change()">按钮</button>
</template>
<script>
import about from './componets/about.vue'
import { computed } from 'vue'//导入computed函数
export default {name: 'App',provide(){return {//显式提供一个计算属性message:computed(() => this.message) }},data(){return {message:"hello!"}},components:{about},methods:{change(){this.message = "修改后的值"}}
}
</script>
<style>
</style>

子组件不变!!

浏览器效果:

三、全局事件总线mitt库

Vue3已经从实例中移除了 on、on、on、off 和 $once 方法,所以我们如果希望继续使用全局事件总线,要通过第三方的库。
mitt库地址:https://www.npmjs.com/package/mitt
GitHub地址:https://github.com/developit/mitt

1.简单使用

1.首先需要安装一下这个库
npm install mitt
2.简单封装一下。
import mitt from 'mitt'const emitter = mitt()export default emitter
3.父组件代码
  • 父组件导入封装的mitt库
  • 通过事件send事件触发emitter.emit(“changeMessage”,this.message)
<template><about></about><h2>app:{{message}}</h2><button @click="send()">按钮</button>
</template>
<script>
import about from './componets/about.vue'
import emitter from './eventbus' //导入mitt库
export default {name: 'App',components:{about},data(){return {message:"APP页面message"}},methods:{send(){emitter.emit("changeMessage",this.message)}}}
</script>
<style>
</style>
 4.子组件代码
  • 子组件在父组件触发事件之前就得监听事件
  • 在监听的时候,父组件触发事件。
  • 触发回调,修改message的值
<template><h2>about:{{message}}</h2>
</template>
<script>
import emitter from '../eventbus' //导入mitt库
export default {name:'AppAbout',data(){return {message:"空"}},created(){emitter.on('changeMessage',(message)=>{this.message = message})}
}
</script>
<style>
</style>
5.浏览器效果

注意:上面的只是通过父子组件来实现通信,类似vue2中的事件总线你可以在任意的组件中监听,触发事件。父子,子孙,兄弟…,任意两个组件通讯都是可以的。

2.响应式事件总线

上面的事件总线是没有响应式的。当App组件中的message发生改变的时候,about组件中的message是不会改变的。
父组件:

<template><about></about><h2>app:{{message}}</h2><button @click="send()">发射</button><button @click="change()">修改</button>
</template>
<script>
import about from './componets/about.vue'
import emitter from './eventbus' //导入mitt库
export default {name: 'App',components:{about},data(){return {message:"APP页面message"}},methods:{send(){emitter.emit("whe",this.message)},change(){this.message = "修改之后的message"}}}
</script>
<style>
</style>

子组件:

<template><h2>about:{{message}}</h2>
</template>
<script>
import emitter from '../eventbus' //导入mitt库
export default {name:'AppAbout',data(){return {message:"空"}},created(){emitter.on('whe',(message)=>{this.message = message})}
}
</script>
<style>
</style>

浏览器效果:

解决办法肯定是有的,只要结合watch监听App组件message的变化,一发生变化就重新发射事件。

修改之后的父组件:

<template><about></about><h2>app:{{message}}</h2><button @click="send(message)">发射</button><button @click="change()">修改</button>
</template>
<script>
import about from './componets/about.vue'
import emitter from './eventbus' //导入mitt库
export default {name: 'App',components:{about},data(){return {message:"APP页面message"}},watch:{message(newData){this.send(newData)}},methods:{send(message){emitter.emit("whe",message)},change(){this.message = "修改之后的message"}}}
</script>
<style>
</style>

浏览器效果:
请添加图片描述

3.取消监听事件

在某些情况下我们可能需要取消监听事件可以通过emitter.of()和emitte.all.clear()

1.使用emitte.all.clear() 取消监听所有事件
父组件不变!!

子组件:

<template><h2>about:{{message}}</h2><button @click="cancel()">{{state}}</button>
</template>
<script>
import emitter from '../eventbus' //导入mitt库
export default {name:'AppAbout',data(){return {message:"空",state:"正在监听"}},created(){emitter.on('whe',(message)=>{this.message = message})},methods:{cancel(){//取消所有的简听this.state = "已取消监听"emitter.all.clear()}}
}
</script>
<style>
</style>

浏览器效果:

2.使用 emitter.of() 取消监听某个事件
父组件不变!!
子组件:

<template><h2>about:{{message}}</h2><button @click="cancel()">{{state}}</button>
</template>
<script>
import emitter from '../eventbus' //导入mitt库
export default {name:'AppAbout',data(){return {message:"空",state:"正在监听"}},created(){emitter.on('whe',this.cb)},methods:{cb(message){this.message = message},cancel(){//取消所有的简听this.state = "已取消监听"emitter.off('whe',this.cb)}}
}
</script>
<style>
</style>

浏览器效果:

四、总结

组件监听的方法上面总共演示了三类。开发中还有一些vuex,localStorage、sessionStorage都是可以进行任意组件的通信。现在就先写到着,后续还会进行补充!!

vue3组件通信的方式 父传子 props 和子传父 $emit 非父子组件的通信Provide和Inject 全局事件总线mitt库相关推荐

  1. Vue3+Typescript学习笔记(十)组件通信--父子组件通信(props,$emit),非父子组件通信(provide和inject,mitt库)

    一.认识组件的嵌套 1. App单独开发 前面我们是将所有的逻辑放到一个App.vue中: 在之前的案例中,我们只是创建了一个组件App: 如果我们一个应用程序将所有的逻辑都放在一个组件中,那么这个组 ...

  2. Vue非父子组件通信的几种方式

    文章目录 1.provide和inject 1.1基本使用 1.2如何处理响应式数据 2.全局事件总线mitt库 2.1安装mitt库,封装eventbus.js工具类 2.2在其中一个组件中触发事件 ...

  3. 「后端小伙伴来学前端了」Vue中利用全局事件总线实现组件之间通信

    月亮啊月亮 你能照见南边,也能照见北边 照见她,你跟她说一声,就说我想她了. 前言 前一篇文章写了 vue 中利用 Props 实现组件之间的通信,那种方式是最简单也是最基础的组件之间的通信方式.父组 ...

  4. React组件通信-非父子组件间的通信

    文章目录 React非父子组件通信 小知识点的补充 Context应用场景 Context相关API Context使用流程 React非父子组件通信 在React中, 非父子组件传递是通过一个API ...

  5. Vue(组件间通信:props、自定义事件、全局事件总线、消息订阅与发布)

    一.props props不仅可以实现父给子传递信息,还可以进行子给父传递信息 1.父给子传递信息: 父组件中给子组件实例传递信息 子组件利用props进行接收组件传递信息(接收方式有三种:数组.对象 ...

  6. vue调用函数怎么传参_Vue(非)父子组件的传值以及方法调用

    1.vue父组件给子组件传值的方法 子组件中通过props接收传值 props:{ username:{ type:String, default:"" } } 2.vue父组件调 ...

  7. Angular 父子组件传值,非父子组件传值

    一.子组件调用父组件,父组件给子组件传值 引入Input header.component.ts import { Component, OnInit, Input, Output } from '@ ...

  8. 初识 Vue(18)---(非父子组件间的传值)

    非父子组件间的传值 常一个应用会以一棵嵌套的组件树的形式来组织:将一个大组件进行拆分 下图这种情况的组件间传值(父子组件间传值) 方法:父组件通过 Props 向子组件传值,子组件通过事件触发向父组件 ...

  9. Vue2.0的三种常用传值方式、父传子、子传父、非父子组件传值

    Vue2.0 传值方式: 在Vue的框架开发的项目过程中,经常会用到组件来管理不同的功能,有一些公共的组件会被提取出来.这时必然会产生一些疑问和需求?比如一个组件调用另一个组件作为自己的子组件,那么我 ...

最新文章

  1. MySQL 跨库分页/ 分表分页/ 跨库分页,为什么这么难?
  2. java——import语句
  3. php签名墙代码,我们是一家人(签名墙)
  4. 如何搭建一个简易的Web框架
  5. JavaFX缺少的功能调查:CSS
  6. 漫画:什么是字符串匹配算法?
  7. 这个春天有点冷,2019年互联网公司裁员清单大全(更新)
  8. 0点睡觉很会养生”苏宁高管的这话让IT人很憋屈
  9. 趣图:程序员桌面对比,iOS vs 安卓
  10. 产品规划立项流程(CDP)
  11. Windows下Python的安装与配置
  12. JDK源码学习系列07----Stack
  13. python网络爬虫实践_《python 网络爬虫从入门到实践》笔记
  14. JAVA基础-多线程中锁机制
  15. “辣条一哥”冲刺IPO,卫龙三年净赚近20亿,小辣条赚大钱
  16. word中快速确认字体颜色的方法
  17. 利用qiime2分析微生物组16S rRNA数据小结
  18. 文件批量改名-bat操作
  19. Swap Adjacent Elements CodeForces - 920C
  20. Vue实战教程:利用自定义实现鼠标拖动元素效果

热门文章

  1. May Cordova anonymously report usage statistics to improve the tool over time?
  2. WebSocket前后端交互
  3. 王者登陆显示服务器超时,王者荣耀超时登陆解决办法
  4. 使用安卓手机的NFC功能进行数据读取操作
  5. javascript操作Long类型数据
  6. 百货集团数字化转型方案
  7. Java-具有新建、打开和保存功能的简单记事本
  8. 初学--Python numpy教程
  9. 车主不怕,出车祸了怎么办
  10. 拆机步骤以及注意事项