Vue组件通信的五种方式

文章目录

  • Vue组件通信的五种方式
    • 一. props/$emit(父子通信)
    • 二. vuex(组件之间通信)
    • 三. 事件总线EventBus(组件之间通信)
    • 四. provide提供/inject注入(祖先与后代之间通信)
    • 五. attrs/attrs/attrs/listeners(父子通信)

一. props/$emit(父子通信)

组件通信中最简单的通信方式,即props/emit,父子通信。

  1. props: 用于子组件获取父组件所传的值

①在子组件标签上采用 属性名=“属性值”

②在props中拿到父组件传过来的属性

使用场景:在父组件中已请求到数据,子组件中需要使用到时,通过props将父组件的数据传递给子组件。

<template><!-- 父组件 --><div class="parent"><!-- =====================1. 在子组件标签上采用 属性名="属性值" --><child name="test"></child></div>
</template><script>
import child from "./child.vue";
export default {components: { child },
};
</script>
<template><!-- 子组件 --><div class="child">{{name}}</div>
</template><script>
export default {props: {// =====================2. 在props中拿到父组件传过来的属性name: {type: String,default: "",},},
};
</script>
  1. $emit: 用于父组件监听子组件抛出的事件

①子组件通过this.$emit(”事件名“),往上抛出事件

②在子组件标签上采用 @子组件抛出的事件名=“父组件接收到子组件事件后所调用的方法”

使用场景:子组件向后端请求数据完成后,告诉父组件,数据请求成功,可以开始处理了。

<template><!-- 子组件 --><div class="child"></div>
</template><script>
export default {methods: {test() {setTimeout(() => {// ===================1. 1秒后数据请求成功,告诉父组件requestSuccess, 可以携带参数paramsthis.$emit("requestSuccess", params);}, 1000);},},
};
</script>
<template><!-- 父组件 --><div class="parent"><!-- =====================2. 在子组件标签上采用 @子组件抛出的事件名="父组件接收到子组件事件后所调用的方法" --><child @requestSuccess="parentReceived"></child></div>
</template><script>
import child from "./child.vue";
export default {components: { child },methods: {parentReceived(params) {console.log("父组件接收成功", params);},},
};
</script>

二. vuex(组件之间通信)

  1. 什么是VueX?

官方解释:Vuex是一个专为Vue.js 应用程序开发的状态管理模式。

个人理解:组件存放公共变量的仓库。

上面讲到的props/emit可以理解为"通信",而VueX则更像是一个的仓库,组件们同时使用这个仓库,组件1在VueX中改变一个值后,其他组件中使用到这个变量的地方都会随之改变。总结来说就是:“公共”、“多个页面使用同一个状态”、“响应式”。

使用场景:登录成功后保存用户的登录状态、购物车中的物品等等

*注意!!VueX中的属性在浏览器刷新之后将全部初始化。

// ==========首先介绍一下VueX中的五大属性
import vuex from 'vuex'const store = vuex.createStore({// 1. state:单一状态树,简单理解就是存放VueX中的变量// 通过this.$store.state.属性名获取state: {count: 0},// 2. getters:类似于vue中的comouted,返回state中的属性做处理之后的结果// 通过this.$store.getters.属性名获取getters: {countAdd(state) {return state.count + 1}},// 3. mutations:组件想改变VueX中的state,唯一的方法就是提交mutation// 通过this.$store.commit(方法名, payload)    可携带参数payloadmutations: {// 第一个参数通常是state,第二个参数可以是this.$store.commit所携带的参数increment(state, payload) {state.count++}},// 4. actions:通过提交mutation来改变state,其中可以加入异步操作,可以理解为升级版的异步mutations// 通过this.$store.dispatch(方法名, payload)    可携带参数payloadactions: {// 与mutations不同,第一个参数通常是vuex对象,第二个参数可以是this.$store.dispatch所携带的参数// 可以理解为context 《=》 this.$storeincrement(context, payload) {context.commit('increment')},// 通常采用对象解构赋值写为:increment2({ commit, state, getters }, payload) {commit('increment')}},// 5. modules:通常在模块化开发时使用,小项目不推荐使用// 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。modules: {modulesA: {state: {},getters: {},mutations: {},actions: {},},modulesB: {state: {},getters: {},mutations: {},actions: {},},}
})
  1. 组件用例
<template><!-- 子组件 --><div class="child"><!-- 子组件如果改变VueX中的userName,此处也会立即变化 -->{{userName}}</div>
</template><script>
export default {computed: {userName() {// 通过this.$store.state.属性名获取return this.$store.state.userName;},},methods: {test() {// 通过this.$store.commit提交mutation来修改this.$store.commit("setUserName", "测试用户")}}
};
</script>
<template><!-- 父组件 --><div class="parent"><!-- 子组件如果改变VueX中的userName,此处也会立即变化 -->{{userName}}</div>
</template><script>
import child from "./child.vue";
export default {components: { child },computed: {userName() {// 通过this.$store.state.属性名获取return this.$store.state.userName;},},
};
</script>

三. 事件总线EventBus(组件之间通信)

EventBus与VueX类似,也可以理解为状态管理仓库,但EventBus并没有state、getters等概念,因此跟VueX相比更像是一个”杂乱“的状态管理仓库。EventBus更像是一个事件中心,组件A向事件中心发送消息,其他组件监听这个消息即可。

使用方法:

  1. 初始化EventBus

①局部事件总线:新创建一个 .js 文件,比如event-bus.js

// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

实质上EventBus是一个不具备 DOM 的组件,它具有的仅仅只是它实例方法而已,因此它非常的轻便。

②全局事件总线:可以直接在项目中的 main.js 初始化EventBus

// main.js
Vue.prototype.$EventBus = new Vue()
  1. 使用用例
// 向EventBus发送消息
EventBus.$emit(事件名, 回调函数)// 监听EventBus接收到的消息
EventBus.$on(事件名, 回调函数)// 移除监听
EventBus.$off(事件名, 回调函数)
<!-- A.vue -->
<template><button @click="sendMsg()">-</button>
</template><script>
// 导入局部EventBus
import { EventBus } from "../event-bus.js";
export default {methods: {sendMsg() {// ==============1. 通过EventBus.$emit(事件名, 参数),向事件总线中抛出事件EventBus.$emit("aMsg", '来自A页面的消息');}}
};
</script>
<!-- B.vue -->
<template><p>{{msg}}</p>
</template><script>
import { EventBus } from "../event-bus.js";
export default {data(){return {msg: ''}},mounted() {// ==============2. 在mounted中创建EventBus的监听器,监听对应事件,并添加回调方法EventBus.$on("aMsg", (msg) => {// A发送来的消息this.msg = msg;});},beforeDestroy() {// ==============3. 关闭页面时,在beforeDestroy中使用EventBus.$off关闭监听器EventBus.$off("aMsg", (msg) => {// A发送来的消息this.msg = msg;});}
};
</script>

*注意:前面提到过,如果使用不善,EventBus会是一种灾难,到底是什么样的”灾难“了?大家都知道vue是单页应用,如果你在某一个页面刷新了之后,与之相关的EventBus会被移除,这样就导致业务走不下去。还要就是如果业务有反复操作的页面,EventBus在监听的时候就会触发很多次,也是一个非常大的隐患。这时候我们就需要好好处理EventBus在项目中的关系。通常会用到,在vue页面销毁时,同时移除EventBus事件监听。

四. provide提供/inject注入(祖先与后代之间通信)

provide与inject通常需要组合使用,以允许一个祖先组件(provide)向其所有子孙后代(inject)注入一个依赖,不论组件层级有多深,后代组件总能拿到祖先所提供的属性。

①在祖先组件中使用provide提供相关属性。

②在后代元素中使用inject拿到祖先组件提供的属性,并注入到当前组件中,即可在当前组件中使用。

*注意:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

使用用例:

<template><!-- 祖先组件 --><div class="ancestors"><parent></parent></div>
</template><script>
import parent from "./parent.vue";
export default {components: { parent },data() {return {userName: "test",};},// ==================1. 祖先组件使用provide提供对应属性,相当于export了provide() {return {userName: this.userName,};},
};
</script>
<template><!-- 父组件 --><div class="parent"><child></child></div>
</template><script>
import child from "./child.vue";
export default {components: { child },// =====================2. 后代元素中使用inject注入该属性,相当于importinject: ["userName"],
};
</script>
<template><!-- 子组件 --><div class="child">{{userName}}</div>
</template><script>
export default {// ====================2. 后代元素中使用inject注入该属性,相当于importinject: ["userName"],
};
</script>

五. attrs/attrs/attrs/listeners(父子通信)

使用场景:

①组件传值时使用: 爷爷在父亲组件传递值,父亲组件会通过attrs获取到不在父亲props里面的所有属性,父亲组件通过在孙子组件上绑定attrs获取到不在父亲props里面的所有属性,父亲组件通过在孙子组件上绑定attrs获取到不在父亲props里面的所有属性,父亲组件通过在孙子组件上绑定attrs 和 $listeners 使孙组件获取爷爷传递的值并且可以调用在爷爷那里定义的方法;

②对一些UI库进行二次封装时使用:比如element-ui,里面的组件不能满足自己的使用场景的时候,会二次封装,但是又想保留他自己的属性和方法,那么这个时候时候attrs和attrs和attrs和listners是个完美的解决方案。

  1. $attrs

一个祖先元素需要向后代传递多个元素时,我们通常采用这种写法:

<template><!-- 祖先组件 --><div class="ancestors"><!-- =====================1. 使用属性名="属性值"的方式逐个传递值 --><parent name="test" age="20" sex="1"></parent></div>
</template><script>
import parent from "./parent.vue";
export default {components: { parent },
};
</script>

而后代元素获取这些父元素传递过来的值时,一般情况下都需要使用props属性逐一获取,这种方式在传递属性较多且属性值复杂时,往往容易出错:

<template><!-- 父组件 --><div class="parent">{{name}}{{age}}{{sex}}<child></child></div>
</template><script>
import child from "./child.vue";
export default {components: { child },// 2. =================使用props逐一获取对应属性props: ["name", "age", "sex"],
};
</script>

attrs实际上就是props的升级版,后代元素取值时,可以不通过props直接使用attrs实际上就是props的升级版,后代元素取值时,可以不通过props直接使用attrs实际上就是props的升级版,后代元素取值时,可以不通过props直接使用attrs取到所有传递下来的属性:

<template><!-- 父组件 --><div class="parent">{{name}}<!-- =====================3. 直接使用$attrs取值 -->{{$attrs.age}}{{$attrs.sex}}<!-- =================4. 可以直接使用v-bind="$attrs"将参数继续向下传递 --><child v-bind="$attrs" head="hhhh"></child><!-- 相当于 <child  name="test" age="20" sex="1" head="hhhh"></child> --></div>
</template><script>
import child from "./child.vue";
export default {components: { child },// 2. 使用props逐一获取对应属性,******注意:props优先级高于$attrs,一旦在props中取了该属性,$attrs便不再有该属性。props: ["name"],
};
</script>

*总结:①$attrs可以一次拿到所有属性(class、style、props已经声明的除外)。

​ ②个人理解:attrs只是一种简写,原理与props类似,不能跨层级传递,需要一层一层使用v−bind="attrs只是一种简写,原理与props类似,不能跨层级传递,需要一层一层使用v-bind="attrs只是一种简写,原理与props类似,不能跨层级传递,需要一层一层使用v−bind="attrs"依次传递。

​ ③如果除attrs外还有其他额外参数需要传递,额外参数与attrs外还有其他额外参数需要传递,额外参数与attrs外还有其他额外参数需要传递,额外参数与attrs中的参数重复时,额外参数优先级更高。

  1. $listeners

与attrs类似,attrs类似,attrs类似,listeners包含了所有父组件中的事件监听器(使用.native修饰的事件除外)。

父组件监听子组件事件时,通常采用这种写法:

<template><!-- 祖先组件 --><div class="ancestors"><!-- =====================1. 使用@事件名="方法名"的方式逐个监听 --><parent @click.native="clickHandle" @test="testHandle"></parent></div>
</template><script>
import parent from "./parent.vue";
export default {components: { parent },
};
</script>

而在子组件中,我们只需要$emit出对应事件名既可以触发父组件对应方法:

<template><!-- 父组件 --><div class="parent"><child></child></div>
</template><script>
import child from "./child.vue";
export default {components: { child },created() {// ===================3. 这里使用this.$listeners就可以直接拿到祖先组件监听的所有事件console.log(this.$listeners)  },methods: {test() {// ==================2. 使用$emit抛出事件,触发父组件方法。this.$emit('test')}}
};
</script>

同attrs一样,可以通过v−on="attrs一样,可以通过 v-on="attrs一样,可以通过v−on="listeners" 将事件监听器继续向下传递,后代元素抛出对应事件后,同样可以触发祖先组件中的方法。

如果想要添加其他事件监听器,可继续绑定事件。但要注意的是,继续绑定的事件和 $listeners 中的事件有重复时,不会被覆盖。当 grandson.vue 触发 customEvent 时,child.vue 和 parent.vue 的事件都会被触发,触发顺序类似于冒泡,先到 child.vue 再到 parent.vue。

Vue组件通信的五种方式相关推荐

  1. vue 组件通信的几种方式

    前言 在vue中,​ 组件的关系不外乎以下三种: 组件是需要通信的,在开发中,常用到的通信方式有:vuex.eventBus.以及props与emit.$parent与$children,除此之外,还 ...

  2. vue组件通信的几种方式

    vue组件通信的几种方式 最近用vue开发项目,记录一下vue组件间通信几种方式 第一种,父子组件通信 一.父组件向子组件传值 1.创建子组件,在src/components/文件夹下新建一个Chil ...

  3. vue组件通信的八种方式

    一.props / $emit 父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信. 1. 父组件向子组件传值 下面通过一个例子说明父组件如何向子组件传递数据:在子组 ...

  4. vue组件通信的几种方法

    vue中我们最常使用的就是父子之间的通信还有全局数据管理vuex了,下面粗略说一下vue组件通信的几种方法 组件通信的几种方式 1.父子组件通信 2.兄弟组件通信 3.跨多层级组件通信 4.任意组件( ...

  5. 【vue】vue组件传值的三种方式

    前言 vue的组件传值分为三种方式:父传子.子传父.非父子组件传值 引用官网的一句话:父子组件的关系可以总结为 prop 向下传递,事件向上传递 父组件通过 prop 给子组件下发数据,子组件通过事件 ...

  6. laydate组件 无法传值_Vue组件通信的几种方式

    组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系: 组件之间的关系 如上图所示,A 和 B.B 和 C. ...

  7. vue组件传值的12种方式

    Vue组件间的12种传值方式 当做到比较大的项目时,一个vue文件里面可能要包含上千行代码,这样不利于后期维护与问题定位,抽离成组件就尤其重要了,我在项目中遇到组件的值如何传递的问题,刚开始接触的时候 ...

  8. React中组件通信的几种方式

    首次发表在个人博客 需要组件之进行通信的几种情况 父组件向子组件通信 子组件向父组件通信 跨级组件通信 没有嵌套关系组件之间的通信 1. 父组件向子组件通信 React数据流动是单向的,父组件向子组件 ...

  9. Vue父子组件通信的三种方式 props、@eventName、$on

    前言 vue 开发中,免不了会用到父子组件的通信,比如调用父类组件的方法或者变量:再比如父组件调用子组件的方法:父子组件相互传递数据等,本文主要通过讲解 三种方式(props.evnetName.ev ...

最新文章

  1. 微信正在用的深度学习框架开源!支持稀疏张量,基于C++开发
  2. Python-HTML CSS题目
  3. Java学习_day005:循环结构
  4. matlab求kcf算法响应图_Kernelized Correlation Filters(KCF)算法
  5. pthread_create函数阻塞了主线程_5个状态,Python 中线程的生命周期
  6. 转载:jsonp详解
  7. FTP测试手机软件画画教程图片,手机绘画SketchBook原创教程
  8. SQL rownum的用法
  9. vf更改当前路径_这份 window.location 备忘单,让你更有条理解决地址路径问题!...
  10. 手机web——自适应网页设计(html/css控制)
  11. k3cloud6.0文件服务器,K3Cloud系统集成配置详解
  12. f1c100A运行linux,荔枝派 Nano 全志 F1C100s 编译运行 Linux 笔记
  13. STM32F4最小系统硬件设计
  14. 在Swing中设置字体的大小
  15. CERC2017 F-Faulty Factorial【数论】
  16. 机器学习数据集划分留出法,留一法,交叉法,自助法
  17. 《Qt5 Cadaques》学习笔记(六):QT QUICK Controls 2
  18. 图论 —— 染色法判断二分图
  19. Matlab-LSB信息隐藏实验
  20. Java五子棋最全教程

热门文章

  1. Jawbone蓝牙音箱:音箱也可“交朋友”
  2. golang优先级队列的实现
  3. C++STL之优先级队列详解
  4. centos7自带邮件服务器,CentOS7搭建简单的邮件服务器
  5. 关于SQL server 内容乱码问题的资料收集
  6. pyhton如何判断字符串中是否只含有数字——isdigit函数的用法及实例
  7. DotNetBar界面按钮设置
  8. HP大中华区总裁孙振耀谈工作和人生
  9. Android自定义实现时光轴效果
  10. Linux系统服务 (DNS解析)