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 获取到数据但却渲染不到页面上的解决方法
Nov 19 Vue.js
Vue使用Element实现增删改查+打包的步骤
Nov 25 Vue.js
如何正确解决VuePress本地访问出现资源报错404的问题
Dec 03 Vue.js
Vue中computed和watch有哪些区别
Dec 19 Vue.js
Vue仿百度搜索功能
Dec 28 Vue.js
如何理解Vue简单状态管理之store模式
May 15 Vue.js
详解Vue router路由
Nov 20 Vue.js
详解Vue的列表渲染
Nov 20 Vue.js
vue3获取当前路由地址
Feb 18 Vue.js
Vue3中toRef与toRefs的区别
Mar 24 Vue.js
vue实现简易音乐播放器
Aug 14 Vue.js
Vue Element plus使用方法梳理
Dec 24 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中批量删除Mysql中相同前缀的数据表的代码
2011/07/01 PHP
php获取用户浏览器版本的方法
2015/01/03 PHP
php判断linux下程序问题实例
2015/07/09 PHP
总结PHP中数值计算的注意事项
2016/08/14 PHP
JQUERY 浏览器判断实现函数
2009/08/20 Javascript
基于jQuery的仿flash的广告轮播代码
2010/11/04 Javascript
javascript 进阶篇3 Ajax 、JSON、 Prototype介绍
2012/03/14 Javascript
JSON无限折叠菜单编写实例
2013/12/16 Javascript
Javascript中的Array数组对象详谈
2014/03/03 Javascript
详解AngularJS中的表格使用
2015/06/16 Javascript
jQuery日历插件datepicker用法详解
2016/03/03 Javascript
浏览器复制插件zeroclipboard使用指南
2016/03/26 Javascript
String字符串截取的四种方式总结
2016/11/28 Javascript
jquery+html仿翻页相册功能
2016/12/20 Javascript
jQuery实现获取h1-h6标题元素值的方法
2017/03/06 Javascript
PHP 实现一种多文件上传的方法
2017/09/20 Javascript
微信小程序 页面滑动事件的实例详解
2017/10/12 Javascript
微信小程序中实现手指缩放图片的示例代码
2018/03/13 Javascript
详解微信小程序框架wepy踩坑记录(与vue对比)
2019/03/12 Javascript
Vue+element 解决浏览器自动填充记住的账号密码问题
2019/06/11 Javascript
Vue之Mixins(混入)的使用方法
2019/09/24 Javascript
微信小程序wx.navigateTo方法里的events参数使用详情及场景
2020/01/07 Javascript
JSONP 的原理、理解 与 实例分析
2020/05/16 Javascript
vue实现tab栏点击高亮效果
2020/08/19 Javascript
python获取当前运行函数名称的方法实例代码
2017/04/06 Python
浅谈python中列表、字符串、字典的常用操作
2017/09/19 Python
python检测空间储存剩余大小和指定文件夹内存占用的实例
2018/06/11 Python
python 统计列表中不同元素的数量方法
2018/06/29 Python
Python如何应用cx_Oracle获取oracle中的clob字段问题
2019/08/27 Python
Python re正则表达式元字符分组()用法分享
2020/02/10 Python
解决Keyerror ''acc'' KeyError: ''val_acc''问题
2020/06/18 Python
丝芙兰新加坡官网:Sephora新加坡
2018/12/04 全球购物
建筑施工实习自我鉴定
2013/09/19 职场文书
实习心得体会
2014/01/02 职场文书
2014年英语教研组工作总结
2014/12/06 职场文书
感恩主题班会教案
2015/08/12 职场文书