前几天有盆友在群里问,vue.$emit和$on可以跨组件完成全局通信,那岂不是可以完全代替vuex,为啥还要用vuex呢。
这个问题就要从eventbu事件总线s和vuex起源说起了。
(趁着尤大的vue3.0还在路上,我们来炒炒现饭)

组件通信

在很久很久以前,在Vue王国里有一个组件塔,有一个组件家族,A,B,C,组件父亲A和儿子B,C生活在不同的层级之间,他们相隔非常远。

父->子

这个时候,父亲想念儿子了,想给他寄信,怎么办呢?简单!在每一个子组件上都有一个props “邮箱”,通过这个邮箱,父亲可以直接投递邮件(data)

    Vue.component('blog-post', {// 在 JavaScript 中是 camelCase 的props: ['postTitle'],template: '<h3>{{ postTitle }}</h3>'})<!-- 在 HTML 中是 kebab-case 的 --><blog-post post-title="我是父亲的消息!"></blog-post>
复制代码

子->父

收到父亲来信后,B,C都非常高兴。想给父亲回话,这时白鸽使者vue.$emit出来了,子组件用vue.$emit传递消息,往上层传播。

this.$emit("todo",{res:"我是儿子的消息"
})
复制代码

接到消息后,父亲得对儿子传递过来的不同类型信息做出不同的回应

    this.$on('todo',function(data){// todo//data => 来自儿子的消息})
复制代码

兄弟

A经常教育B和C,说兄弟之间要多联系,增加感情,但是$emit又只能向上层传递消息,住在同一层的兄弟两又该怎么联系呢?

eventbu事件总线

这时候有一个智者想到了一个方法,既然你们都用$emit这个方法,我何不直接开个顺丰快递呢? 这时候vue eventbus事件总线出来了,利用一个游离在组件塔外的vue实例,构造了一个bus总线,儿子的消息通过$emit给bus总线.

B.$root.bus.$emit('todo')
复制代码

这时候父亲所得到的消息是由bus总线发出的,并设置响应事件

A.$root.bus.on('todo',function(){})
复制代码

这样父亲儿子就可以轻轻松松的联系了
那最关键的问题是,兄弟之间怎么联系呢?
总线的智者这时候跳出来说,顾客就是上帝,不管是父亲儿子都可以使用我们顺丰快递总线,这样也就实现了兄弟组件之间的通信

B.$root.bus.$emit('todo')
// 兄弟C也能收到这个消息
C.$root.bus.on('todo',function(){})
复制代码

problem?

这个时候回到本文关键,为什么eventBus这么好的东西我们还要使用vuex呢?
以下内容参照 vuex-basics-tutorial
最开始,我们的项目可能是简简单单这样的

在过了很长一段时间之后,王国不断发展,项目越来越大,组件塔里的组件越来越多,他们长得也越来越复杂,整个王国变得乱七八糟,项目结构变成下面这个样子。不同组件之间通信越来越多,代码段里不断的出现$emit和$on导致了以下几个主要问题

1. 代码逻辑性极具下降,可阅读性变低
2. 对于每一个action父组件都需要一个on(或dispatch)一个事件来处理
3. 你将很难查找到每一个事件是从哪里触发,满篇都是业务逻辑
复制代码

简单的例子

举个简单的例子。你的公司原来有一个display组件,他的作用是展现App根组件上increment的当前值。你新招了两个新员工,给他们分配了两个任务。

  1. 你让小A开发一个新的计数器在一个新的组件(childDisplay)里运用,实现点击一次增加increment一次,并在组件内展现increment当前的数字。这个计数器订阅了increment,点击计数器成功让display和childDisplay显示increment增加1后的数字。
    小A开开心心迅速的完成了这个任务commit然后push了
  2. 你跟小B说,我需要一个按钮组件,这个按钮组件向app实例emit了一个reset事件,这个事件将重置App上increment为0
    好的,小B也开开心心的commit然后push了
  3. 这个时候你会发现当你点击A组件时,在display和childDiplay上都成功显示了increment增加1以后的数字,但点击B组件触发reset事件时,根组件上的increment重置为了0,但由于小B并不知道A组件也订阅了increment这个数据,导致A组件状态没有更新。

vuex

为了防止这些问题,这个时候,国王尤小右站了出来,他借助隔壁flux王国的思想,带领全国的智者研究出了一个新的方式来解决这种混乱的问题。那就是vuex了。

按照定义来说

  1. store是一个仓库,仓库保存着项目的数据(store.state)
  2. (严格模式)为了解决无法追踪状态变化的问题,仓库里的数据不直接通过修改store.state来改变,而是通过commit一个动作告诉仓库,将会报错 [vuex] Do not mutate vuex store state outside mutation handlers
  3. 仓库收到了commit的动作后,将会在store.mutation里查找对应事件,并改变store.state

回到简单的例子

解决方案1(简单store模式)

为了解决上述问题,我们做出了几个有意思的改变。(state)

  1. 在store里定义了一个常量store
  2. 在本地数据里定义了一个叫做sharedState的变量,是store.state里的映射
  3. 因为sharedState是vue的数据,所以他让store.state也变成了一个响应式数据,当store.state里数据发生改变时,vue将会自动的更新sharedState里的数据。

这样,原有的问题就解决了,A组件和B组件订阅的increment不再是根组件上的数据了,而是仓库的数据。当仓库数据改变时,vue将自动更新到每个订阅了increment数据的组件上。

// 这是父级display组件
<template>Count is {{ sharedState.counter }}
</template><script>
import store from '../store'export default {data () {return {sharedState: store.state}}
}
</script>
复制代码
// 这是A组件
import store from '../store'
<template>Count is {{ sharedState.counter }}
</template>
export default {data () {return {sharedState: store.state}},methods: {activate () {this.sharedState.counter += 1}}
}
复制代码
// 这是B组件
import store from '../store'
export default {data () {return {sharedState: store.state}},methods: {reset () {this.sharedState.counter = 0}}
}
复制代码
方案1变形

上述的方式就是最好的了吗?试想当A,B在这家公司开发了无数多个reset组件和计数器组件后离职了。这时候招来了一个新的员工C,你跟C说,我想要所有的increment大小不超过100,难道C要对所有组件进行重构,判断大小吗,这是非常荒谬的选择。这时候我们引入了新的方法。(mutation)

var store = {state: {counter: 0},increment: function () {if (store.state.counter < 100) {store.state.counter += 1;}},reset: function () {store.state.counter = 0;}
}export default store
复制代码

根据上面的衍生,vuex就慢慢成型了

我们重新创建store.js

import Vuex from 'vuex'
import Vue from 'vue'Vue.use(Vuex)var store = new Vuex.Store({state: {counter: 0},mutations: {INCREMENT (state) {state.counter ++}}
})export default store
复制代码

我们看下这里做了什么样的操作

  1. 我们引入了一个vuex模块,并作为vue插件激活
  2. 我们的仓库store不再是一个普通的jsonObject而是一个vuex.store的实例
  3. 采用了mutation,用于改变state

why better ?

  1. 如果在开发过程中保留了所有状态的副本,我们可以像super hero一样如时空穿梭般对代码进行调试,记录每一次状态的变化
  2. 你可以构建一个中间件,比如一个日志打印器,在每次用户提交一个action时记录操作,当出现问题时你将会更加容易的调试与fix bug
  3. 强制要求你把所有action通过一个store管理,这样团队开发将会更加便捷与明了

总结

通过长篇的分析我们可以得出本文结论了。

  1. vuex是官方推出的,事件总线是高手在民间
  2. 在大型应用方面,vuex确实是一个比EventBus更好的解决方案
  3. vuex更加易于调试与管理
  4. Vuex并不是最佳的解决方案,在某些小型应用上,你可能只有小部分的数据交互,甚至只有一个登录状态储存,那样事件总线或者简单状态管理都是值得推荐的。
    最后说一句,vuex真香。 ps:这只是笔者的见解,有什么问题欢迎大家踊跃提出指正。?

转载于:https://juejin.im/post/5c09cb73518825159512778b

EventBus Vuex?相关推荐

  1. eventBus VSvueX

    EventBus & Vuex? 组件通信 在很久很久以前,在Vue王国里有一个组件塔,有一个组件家族,A,B,C,组件父亲A和儿子B,C生活在不同的层级之间,他们相隔非常远. 父->子 ...

  2. vue-music 音乐网站

    在学习完vueJS,一直想做个项目来锻炼一下,选来选去,还是做个网易云音乐,其间遇到了很多坑,也逐渐接受了vue这种组件化的思想以及从Dom操作转换为用数据去驱动视图.并且在某部分基础组件上借鉴(搬运 ...

  3. 七种Vue3传值方式

    七种Vue3传值方式 props emit v-model refs provide/inject eventBus vuex/pinia(状态管理工具) Props方式 Props方式是Vue中最常 ...

  4. vue组件通信大总结

    文章目录 1. props / $emit 2. sync / update 3. provide / inject 4. $attrs / $listeners 5. $children / $pa ...

  5. 2018web前端面试题总结

      web面试题 css面试 一.css盒模型 css中的盒子模型包括IE盒子模型和标准的W3C盒子模型. border-sizing: border-box, inherit, content-bo ...

  6. vue的组件通信方式

    组件通信方式 一.props / $emit 1. 父组件向子组件传值 2. 子组件向父组件传值 二. $children / $parent 三.provide/ inject 四.ref / re ...

  7. 超实用的 Vue 组件通信方式大汇总(8种)

    文章目录 前言 一.Vue组件关系 二.Vue组件通信方式 1. props / $emit 1.1 props 父传子 1.2 $emit 子传父 1.3 父子组件双向绑定 1.3.1 v-mode ...

  8. 前端基础知识点-每天一个基本知识点(100+个前端小知识,你是否都知道?)

    文章目录 前言 第一回合 一.知识点:cookie(21/09/06) 二.知识点:节流和防抖(21/09/07) 三.知识点:var和let以及const(21/09/08) 四:知识点:深拷贝和浅 ...

  9. 熬夜整理的vue面试题

    Vue-router 路由模式有几种 vue-router 有 3 种路由模式:hash.history.abstract,对应的源码如下所示 switch (mode) {case 'history ...

最新文章

  1. SpringMVC 中的异常处理
  2. 如何创建高质量的TypeScript声明文件(六) - 示例
  3. 图论--关于最长路的探讨
  4. 苹果手机vnc进linux的服务器,linux服务器vnc远程连接,怎么使用linux服务器进行vnc远程连接?...
  5. Jenkins系列二:SVN+Maven+Tomcat自动构建和部署
  6. OpenLayers自定义投影,转换OpenLayers中加载的OSM的默认投影坐标
  7. oracle同义词表不存在,Oracle同义词的使用
  8. 深度学习在摄影技术中的应用与发展
  9. 普通话测试-短文60篇文章,附带拼音(51-60篇)
  10. 任务栏优化工具TrueLaunchBar
  11. php redis 搜索,一步步实现 Redis 搜索引擎
  12. NR PRACH(六) type 2(2-step) RA基本过程及时频域映射
  13. 缓解 WPF 应用程序中的空域问题
  14. 【战国策】之《齐策·昭阳为楚伐魏》
  15. C语言笔记含源码(变量、输入输出、分支、循环、函数、数组、指针、字符串、结构体)小总结
  16. Python—SVD分解压缩图片
  17. 错误:The ‘pycocotools>=2.0‘ distribution was not found and is required by the application
  18. JDBC基本原理及使用
  19. 要启用实时(jit)调试 该应用计算机,这个是什么意思?怎么解决?有关调用实时(JIT)调试而不是此...
  20. 松下A5伺服器调试软件

热门文章

  1. sflow-rt 3.0 安装
  2. VBA案例8:实现在ppt中写vba,控制动态图
  3. 计算机专业开题报告这么写,有效有用还能过
  4. NYOJ - [第八届河南省程序设计大赛]Distribution(水题)
  5. 一个简单的全排列算法
  6. signal信号的基础知识
  7. java 项目中遇到的问题 和解决方案_Java开发遇到的问题及解决方案
  8. ultron,奥创,ultron官网,奥创官网,奥创中国区官网,ultron中国区官网,奥创公链,ultron公链,ulx,ultron奥创,海洋renhe333333
  9. RSSI 平面 三点定位算法(C语言、JS源码例程)
  10. 语音信号处理--基音检测实验