详解如何实现一个简单的 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 相关文章推荐
Javscript调用iframe框架页面中函数的方法
Nov 01 Javascript
JavaScript调用浏览器打印功能实例分析
Jul 17 Javascript
javascript绘制漂亮的心型线效果完整实例
Feb 02 Javascript
jQuery在ie6下无法设置select选中的解决方法详解
Sep 20 Javascript
JS+HTML5实现的前端购物车功能插件实例【附demo源码下载】
Oct 17 Javascript
js实时获取窗口大小变化的实例代码
Nov 18 Javascript
JavaScript的变量声明提升问题浅析(Hoisting)
Nov 30 Javascript
简单实现jQuery弹窗效果
Oct 30 jQuery
浅谈Vue内置component组件的应用场景
Mar 27 Javascript
详解Vue.js中.native修饰符
Apr 24 Javascript
浅谈Vue数据响应思路之数组
Nov 06 Javascript
Vue 使用Props属性实现父子组件的动态传值详解
Nov 13 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
WordPress中获取所使用的模板的页面ID的简单方法
2015/12/31 PHP
获取页面高度,窗口高度,滚动条高度等参数值getPageSize,getPageScroll
2006/09/22 Javascript
JQuery学习笔记 nt-child的使用
2011/01/17 Javascript
jquery入门—访问DOM对象方法
2013/01/07 Javascript
js带按钮的提示框可供选择示例代码
2013/09/17 Javascript
asp.net刷新本页面的六种方法总结
2014/01/07 Javascript
nodejs下打包模块archiver详解
2014/12/03 NodeJs
10条建议帮助你创建更好的jQuery插件
2015/05/18 Javascript
JavaScript编程中实现对象封装特性的实例讲解
2016/06/24 Javascript
JS触发服务器控件的单击事件(详解)
2016/08/06 Javascript
JavaScript 对象详细整理总结
2016/09/29 Javascript
使用BootStrap进行轮播图的制作
2017/01/06 Javascript
vue2.0嵌套路由实现豆瓣电影分页功能(附demo)
2017/03/13 Javascript
详解webpack的配置文件entry与output
2017/08/21 Javascript
浅谈Node.js CVE-2017-14849 漏洞分析(详细步骤)
2017/11/10 Javascript
详解VUE 对element-ui中的ElTableColumn扩展
2018/03/28 Javascript
使用Sonarqube扫描Javascript代码的示例
2018/12/26 Javascript
微信小程序工具函数封装
2019/10/28 Javascript
微信小程序 自定义弹窗实现过程(附代码)
2019/12/05 Javascript
jquery实现拖拽小方块效果
2020/12/10 jQuery
[06:37]2014DOTA2国际邀请赛 昔日王者渴望重回巅峰
2014/07/12 DOTA
[02:24]DOTA2亚洲邀请赛 NAVI战队出场宣传片
2015/02/07 DOTA
python list转dict示例分享
2014/01/28 Python
python+selenium实现QQ邮箱自动发送功能
2019/01/23 Python
Python3.5内置模块之time与datetime模块用法实例分析
2019/04/27 Python
python自动结束mysql慢查询会话的实例代码
2019/10/27 Python
Python Numpy数组扩展repeat和tile使用实例解析
2019/12/09 Python
python异常处理和日志处理方式
2019/12/24 Python
导入tensorflow:ImportError: libcublas.so.9.0 报错
2020/01/06 Python
python 使用递归回溯完美解决八皇后的问题
2020/02/26 Python
css3 border-image使用说明
2010/06/23 HTML / CSS
HTML5给汉字加拼音收起展开组件的实现代码
2020/04/08 HTML / CSS
End Clothing美国站:英国男士潮牌商城
2018/04/20 全球购物
欢迎横幅标语
2014/06/17 职场文书
班子个人四风问题整改措施
2014/10/04 职场文书
中学生自我评价范文
2015/03/03 职场文书