详解如何实现一个简单的 vuex


Posted in Javascript onFebruary 10, 2018

首先我们需要知道为何要使用 vuex。父子组件通信用 prop 和自定义事件可以搞定,简单的非父子组件通信用 bus(一个空的 Vue 实例)。那么使用 vuex 就是为了解决复杂的非父子组件通信。

仅仅会使用 vuex 没什么,看过文档敲敲代码大家都会。难道你就不想知道 vuex 是如何实现的?!

抛开 vuex 的源码,我们先来想想如何实现一个简单的 "vuex"。有多简单呢,我不要 getter、mutation、action 等,我只要 state 就行了。

非父子组件通信

在实现之前,我们得来温故一下 bus 的实现,借用官网的例子:

var bus = new Vue()

// 触发组件 A 中的事件
bus.$emit('id-selected', 1)

// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
 // ...
})

遥想当年,实例化后的 bus 不知放哪好,最后无奈将其放到了 window 下,一直 window.bus 的使用。虽然这样也没问题,但还是影响到了全局作用域。

突然的某一天,我发现可以挂载在 vue 的根实例下(从此告别 window.bus),于是便有了:

var app = new Vue({
 el: '#app',
 bus: bus
})

// 使用 bus
app.$options.bus

// or
this.$root.$options.bus

然后又发现了,bus 其实不只是 on 事件才可以通信。其实 bus 是一个 Vue 实例,其中 data 是响应的。比如在 app 这个根实例下有两个非父子组件,都使用到了 bus 的 data,那么它们是响应同步的。

var bus = new Vue({
 data: {
  count: 0
 }
})

以上,子组件 a 修改了 count,如果子组件 b 有用到 count,那么它就能响应到最新 count 的值。

说了这么多,你还没发现吗?这个不就是实现了非组件之间通信,vuex 的 state 吗?!

封装 bus

是的,把刚刚的 bus 封装一下,这个就是一个最简单的 "vuex" (仅仅只有 state 的功能)。首先,我们将有一个根实例 app ,实例下有两个非父子组件 childA 和 childB 。

html 代码的实现如下:

<div id="app">
 <child-a></child-a>
 <child-b></child-b>
</div>

非父子组件的实现

然后是两个非父子组件和 app 的实现,子组件都使用到了 bus 的 count,这里用 store.state 表示,跟 vuex 一致:

// 待实现
const store = new Store(Vue, {
 state: {
  count: 0
 }
})

// 子组件 a
const childA = {
 template: '<button @click="handleClick">click me</button>',
 methods: {
  handleClick () {
   this.$store.state.count += 1
  }
 }
}

// 子组件 b
const childB = {
 template: '<div>count: {{ count }}</div>',
 computed: {
  count () {
   return this.$store.state.count
  }
 }
}

new Vue({
 el: '#app',
 components: {
  'child-a': childA,
  'child-b': childB
 },
 store: store
})

看到代码里还有一个 Store 待实现。所需要的参数,因为这里懒得用 Vue.use() ,所以直接将 Vue 作为参数传入以供使用,然后第二个参数跟我们使用 vuex 传入的参数一致。

Store 的实现

接下来就是 Store 的实现,两步实现:

  1. 创建一个 bus 实例;
  2. 让子组件都能访问到 this.$store。

第 1 步骤上面已经有了,第 2 步骤主要用到了 Vue.mixin 来全局混入,但仅仅只是找到有 store 的根实例并赋值 Vue 原型上的 store,也能够让根实例 app 不用专门写 mixins 混入。

class Store {
 constructor (Vue, options) {
  var bus = new Vue({
   data: {
    state: options.state
   }
  })

  this.install(Vue, bus)
 }
 
 install (Vue, bus) {
  Vue.mixin({
   beforeCreate () {
    if (this.$options.store) {
     Vue.prototype.$store = bus
    }
   }
  })
 }
}

实现的 Store 就是一个简单的 "vuex",它拥有了 vuex 的 state,足够让非父子组件之间进行简单通信。

在 Store 的构造函数里创建一个 bus 实例,并将其注入 Vue 的原型,实现了组件都能访问到 this.$store 即 bus 实例。 this.$store 就是一个 Vue 实例,所以访问了 this.$store.state.count 实际上就是访问到了 data,从而实现了非父子组件之间的响应同步。全部源码参考这里 。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 封装Ajax传递的数据代码
Jun 05 Javascript
JavaScript函数获取事件源的小例子
May 14 Javascript
AngularJS基础知识
Dec 21 Javascript
使用console进行性能测试
Apr 27 Javascript
JS日期格式化之javascript Date format
Oct 01 Javascript
ES6中如何使用Set和WeakSet
Mar 10 Javascript
jQuery实现弹出窗口弹出div层的实例代码
Jan 09 Javascript
javascript容错处理代码(屏蔽js错误)
Jan 20 Javascript
vue.js的computed,filter,get,set的用法及区别详解
Mar 08 Javascript
解决vue中使用swiper插件问题及swiper在vue中的用法
Apr 04 Javascript
Vue+webpack+Element 兼容问题总结(小结)
Aug 16 Javascript
vue不操作dom实现图片轮播的示例代码
Dec 18 Javascript
vue实现微信分享朋友圈,发送朋友的示例讲解
Feb 10 #Javascript
使用 vue.js 构建大型单页应用
Feb 10 #Javascript
javascript中的隐式调用
Feb 10 #Javascript
VUEJS 2.0 子组件访问/调用父组件的实例
Feb 10 #Javascript
webpack之devtool详解
Feb 10 #Javascript
React组件refs的使用详解
Feb 09 #Javascript
详解vue-cli项目中的proxyTable跨域问题小结
Feb 09 #Javascript
You might like
mysqli_set_charset和SET NAMES使用抉择及优劣分析
2013/01/13 PHP
PHP PDO fetch 模式各种参数的输出结果一览
2015/01/07 PHP
jquery怎样实现ajax联动框(一)
2013/03/08 Javascript
js简单实现用户注册信息的校验代码
2013/11/15 Javascript
javascript读取Xml文件做一个二级联动菜单示例
2014/03/17 Javascript
JQuery给元素绑定click事件多次执行的解决方法
2014/05/29 Javascript
javascript动态修改Li节点值的方法
2015/01/20 Javascript
jQuery实现字符串按指定长度加入特定内容的方法
2015/03/11 Javascript
javascript求日期差的方法
2016/03/02 Javascript
js中的关联数组与普通数组详解
2016/07/27 Javascript
AngularJS基础 ng-model 指令详解及示例代码
2016/08/02 Javascript
基于JS实现横线提示输入验证码随验证码输入消失(js验证码的实现)
2016/10/27 Javascript
JavaScript 最佳实践:帮你提升代码质量
2016/12/03 Javascript
详解Node.js中的Async和Await函数
2018/02/22 Javascript
详解如何webpack使用DllPlugin
2018/09/30 Javascript
Vue项目引发的「过滤器」使用教程
2019/03/12 Javascript
webpack 如何同时输出压缩和未压缩的文件的实现步骤
2020/06/05 Javascript
Nodejs + sequelize 实现增删改查操作
2020/11/07 NodeJs
[36:17]DOTA2上海特级锦标赛 - VGL音乐会全集
2016/03/06 DOTA
python基础教程之字典操作详解
2014/03/25 Python
pycharm下打开、执行并调试scrapy爬虫程序的方法
2017/11/29 Python
Python爬豆瓣电影实例
2018/02/23 Python
python如何在循环引用中管理内存
2018/03/20 Python
python实现连连看辅助(图像识别)
2020/03/25 Python
Python使用scipy模块实现一维卷积运算示例
2019/09/05 Python
线程安全及Python中的GIL原理分析
2019/10/29 Python
使用python执行shell脚本 并动态传参 及subprocess的使用详解
2020/03/06 Python
python 利用jieba.analyse进行 关键词提取
2020/12/17 Python
Biblibili视频投稿接口分析并以Python实现自动投稿功能
2021/02/05 Python
python 利用matplotlib在3D空间绘制二次抛物面的案例
2021/02/06 Python
亚马逊西班牙购物网站:amazon西班牙
2017/03/06 全球购物
瑞士首家网上药店折扣店:McDrogerie
2020/12/22 全球购物
关于运动会的广播稿
2014/09/22 职场文书
预防职务犯罪警示教育心得体会
2016/01/15 职场文书
利用JavaScript写一个简单计算器
2021/11/27 Javascript
服务器nginx权限被拒绝解决案例
2022/09/23 Servers