Vue如何实现组件间通信


Posted in Vue.js onMay 15, 2021

1. 父子间通信

最常见的就是父子之间的通信,通信是双向的数据传递。

1.1 父组件 --> 儿子组件

父组件向儿子组件传递数据的方式就是 通过 Prop 向子组件传递数据。

//child.vue
<template>
    <div>
        我是儿子,我收到来自父亲的数据为 {{value}}
    </div>
</template>

<script>
export default {
    props:{
        value: String
    }
}
//App.vue
<template>
  <div id="app">
    <Child :value="x" />
  </div>
</template>

<script>
import Child from './components/Child'
export default {
  data(){
    return {
      x: 'hi,child'
    }
  },
  components:{
    Child
  }
}
</script>

1.2 儿子组件 --> 父组件

儿子组件向父组件传递数据的方式就是通过子组件内 $emit 触发自定义事件,子组件使用时 v-on 绑定监听自定义事件。

这里的 v-on 事件通信是在子组件使用时作为子组件的事件属性自动进行监听的。

因此儿子组件向父组件传递数据,依赖于子组件使用时的自定义事件属性。

//child.vue
<template>
    <div>
        我是儿子,我收到来自父亲的数据为 {{value}}
        <button @click="sayHi">
            向父组件打招呼
        </button>
    </div>
</template>

<script>
export default {
    props:{
        value: String
    },
    methods:{
        sayHi(){
            this.$emit('sayHi','hi,parent!');
        }
    }
}
</script>
//App.vue
<template>
  <div id="app">
    我是父组件,我收到子组件传来的数据为 {{y}}
    <Child :value="x" @sayHi="y = $event"/>
  </div>
</template>

<script>
import Child from './components/Child'
export default {
  data(){
    return {
      x: 'hi,child',
      y: ''
    }
  },
  components:{
    Child
  }
}
</script>

Vue如何实现组件间通信

2. 爷孙间通信

爷孙间通信,可以使用两次 v-on 通信,爷爷爸爸通信,然后爸爸儿子通信。

也可使用下方的任意组件间通信的方式。

3. 任意组件间通信

任意组件间通信就不再区分是 A 向 B 通信,还是 B 向 A 通信,而是通用的方式,谁想发送数据就使用对应的 API 发送数据,谁想要接收什么数据,就使用对应的 API 接收。

任意组件间通信有两种方式,一种是使用 EventBus 发布订阅模式通信,一种是使用 Vuex 通信。

3.1 EventBus

EventBus ,从字面意思理解就是事件公交车,所有触发的事件传递的数据都从前门上车保存到公交车上,然后通过监听对应事件提供的出口让对应的事件数据下车。

EventBus,实际意思是发布和订阅模式,就是谁想把数据传递出去,就要通过触发自定义事件的 API 进行数据的发布;谁需要接收该数据信息的,就通过事件监听的 API 进行数据的监听,一旦检测到监听的数据发布出来,就会接收,这就是数据的订阅。

EventBus 通信方式最重要是搞明白发布和订阅的接口 API,在 Vue 中,Vue 实例有提供两个接口,即 $emit$on ,因此可以新创建一个空的 Vue 实例,来获得这两个接口。

const eventBus = new Vue();
eventBus.$emit(eventName, […args]) //发布事件
eventBus.$on(event, callback)      //订阅事件

实例如下:

// eventBus.js
import Vue from 'vue'
export const eventBus = new Vue();
//child
<template>
    <div>
        我是儿子,我收到来自父亲的数据为 <strong>{{value}}</strong>
        <button @click="sayHi">
            向父组件打招呼
        </button>
        <button @click="sibling">
            向兄弟组件打招呼
        </button>
    </div>
</template>

<script>
import {eventBus} from '../eventBus.js'
export default {
    props:{
        value: String
    },
    methods:{
        sayHi(){
            this.$emit('sayHi','hi,parent!');
        },
        sibling(){
            eventBus.$emit('sibling','hi,brother');
        }
    }
}
</script>

<style scoped>
    strong{
        color: red;
    }
</style>
//sibling
<template>
    <div>
        我是兄弟组件,我收到来自儿子组件的数据信息为 <strong>{{x}}</strong> 
    </div>
</template>

<script>
import {eventBus} from '../eventBus.js'
export default {
    data(){
        return {
            x: ''
        }
    },
    mounted(){
        eventBus.$on('sibling', (msg)=>{
            this.x = msg;
        })
    }
}
</script>

<style scoped>
    strong{
            color: green;
    }
</style>
//parent
<template>
  <div id="app">
    我是父组件,我收到子组件传来的数据为 <strong>{{y}}</strong>
    <Child :value="x" @sayHi="y = $event"/>
    <Sibling></Sibling>
  </div>
</template>

<script>
import Child from './components/Child'
import Sibling from './components/Sibling'
export default {
  data(){
    return {
      x: 'hi,child',
      y: ''
    }
  },
  components:{
    Child,
    Sibling
  }
}
</script>

<style scoped>
    strong{
            color: blue;
    }
</style>

Vue如何实现组件间通信

关于 EventBus 这部分,可能存在这样一个疑问,既然 Vue 实例中都有 $emit 和 $on,为什么不直接用 this.$emit 触发事件, this.$on 接收事件呢?还非得要额外一个空实例 eventBus = new Vue() 。那是因为,Vue 中每个组件都是一个单独的 Vue 实例,你在这个 Vue 实例中触发该实例的 emit 事件,另外一个实例的 on 事件是接收不到的,不在一辆公交车上,怎么能进行事件通信呢?因此就必须要一个公共的公交车,也就是事件总线。

上述实例中的 eventBus 的使用方法是局部的 eventBus,谁要用到 eventBus 要自己手动引入。也可以将 eventBus 做成全局的,比如挂在 vue 的原型上。

//main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

Vue.prototype.$eventBus = new Vue();//添加这句,一定要在下方的 new Vue 前。

new Vue({
  render: h => h(App),
}).$mount('#app')
//child
sibling(){
    this.$eventBus.$emit('sibling','hi,brother');
}
//sibling
mounted(){
    this.$eventBus.$on('sibling', (msg)=>{
        this.x = msg;
    })
}

除了上述的添加属性到 Vue 原型的方式外,还可以使用 Object.defineProperty() 为 Vue 原型添加属性。

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

let eventBus = new Vue()
Object.defineProperty(Vue.prototype,'$eventBus',{
  get(){
    return eventBus
  }
})

new Vue({
  render: h => h(App),
}).$mount('#app')

3.2 Vuex

Vue 组件间的通信也可使用专门为 vue.js 应用程序开发的状态管理模式:Vuex。Vuex 的使用比较复杂,详细可见 Vuex 博客。Vuex 适用于大型的复杂的 Vue 项目的状态管理。对于一些中小型的应用程序,可以根据 Vuex 的原理自定义 store 模式进行状态管理,vue 自定义状态管理,可详见 Vue 简单状态管理—store模式 博客。

无论是 Vuex 还是 自定义 store模式 ,其实现组件间通信的原理都是通过共享数据的方式实现的。组件间使用相同的数据源,当一个组件改变数据时,另一个组件依赖的数据源也就改变了。

以上就是Vue如何实现组件间通信的详细内容,更多关于Vue组件间通信的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue组件中节流函数的失效的原因和解决方法
Dec 02 Vue.js
vuex Module将 store 分割成模块的操作
Dec 07 Vue.js
vue项目中openlayers绘制行政区划
Dec 24 Vue.js
vue中watch的用法汇总
Dec 28 Vue.js
详解为什么Vue中的v-if和v-for不建议一起用
Jan 13 Vue.js
原生JS封装vue Tab切换效果
Apr 28 Vue.js
Vue实现tab导航栏并支持左右滑动功能
Jun 28 Vue.js
Vue3.0中Ref与Reactive的区别示例详析
Jul 07 Vue.js
Vue Element-ui表单校验规则实现
Jul 09 Vue.js
如何用vue实现网页截图你知道吗
Nov 17 Vue.js
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
Apr 11 Vue.js
vue postcss-px2rem 自适应布局
May 15 Vue.js
详解Vue的sync修饰符
May 15 #Vue.js
深入理解Vue的数据响应式
May 15 #Vue.js
详解Vue的options
May 15 #Vue.js
vue实现无缝轮播效果(跑马灯)
May 14 #Vue.js
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
vue实现可拖拽的dialog弹框
You might like
php 更新数据库中断的解决方法
2009/06/05 PHP
PHP动态柱状图实现方法
2015/03/30 PHP
php自定义时间转换函数示例
2016/12/07 PHP
Laravel 实现数据软删除功能
2019/08/21 PHP
js中的escape及unescape函数的php实现代码
2007/09/04 Javascript
利用JS重写Cognos右键菜单的实现代码
2010/04/11 Javascript
页面载入结束自动调用js函数示例
2013/09/23 Javascript
jQuery替换字符串(实例代码)
2013/11/13 Javascript
jQuery中使用data()方法读取HTML5自定义属性data-*实例
2014/04/11 Javascript
js常用数组操作方法简明总结
2014/06/20 Javascript
Javascript基础知识(一)核心基础语法与事件模型
2014/09/29 Javascript
jquery实现很酷的网页顶部图标下拉菜单效果
2015/08/22 Javascript
js实现的下拉框二级联动效果
2016/04/30 Javascript
Bootstrap中点击按钮后变灰并显示加载中实例代码
2016/09/23 Javascript
简单谈谈JS数组中的indexOf方法
2016/10/13 Javascript
jQuery展示表格点击变色、全选、删除
2017/01/05 Javascript
用vue快速开发app的脚手架工具
2018/06/11 Javascript
javascript实现摄像头拍照预览
2019/09/30 Javascript
jQuery/JS监听input输入框值变化实例
2019/10/17 jQuery
vue-以文件流-blob-的形式-下载-导出文件操作
2020/08/07 Javascript
vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能
2020/11/16 Javascript
python 判断是否为正小数和正整数的实例
2017/07/23 Python
在PyCharm中批量查找及替换的方法
2019/01/20 Python
基于Jquery和Css3代码制作可以缩放的搜索框
2015/11/19 HTML / CSS
Lookfantastic瑞典:英国知名美妆购物网站
2018/04/06 全球购物
网站域名和主机:Domain.com
2019/04/01 全球购物
当我正在为表建立索引的时候,SQL Server 会禁止对表的访问吗
2014/04/28 面试题
优秀的自荐信要注意哪些
2014/01/03 职场文书
大学活动总结格式
2014/04/29 职场文书
爱国演讲稿400字
2014/05/07 职场文书
护士节策划方案
2014/05/19 职场文书
小学竞选班干部演讲稿
2014/08/20 职场文书
社区三八妇女节活动总结
2015/02/06 职场文书
初中重阳节活动总结
2015/05/05 职场文书
MySQL Threads_running飙升与慢查询的相关问题解决
2021/05/08 MySQL
详解Mysq MVCC多版本的并发控制
2022/04/29 MySQL