首先咱们须要知道为什么要使用 vuex。父子组件通讯用 prop 和自定义事件能够搞定,简单的非父子组件通讯用 bus(一个空的 Vue 实例)。那么使用 vuex 就是为了解决复杂的非父子组件通讯。html
仅仅会使用 vuex 没什么,看过文档敲敲代码你们都会。难道你就不想知道 vuex 是如何实现的?!前端
抛开 vuex 的源码,咱们先来想一想如何实现一个简单的 "vuex"。有多简单呢,我不要 getter、mutation、action 等,我只要 state 就好了。vue
非父子组件通讯vuex
在实现以前,咱们得来温故一下 bus 的实现,借用官网的例子:app
`var` `bus =` `new` `Vue()` `// 触发组件 A 中的事件` `bus.$emit(``'id-selected'``, 1)` `// 在组件 B 建立的钩子中监听事件` `bus.$on(``'id-selected'``,` `function` `(id) {` `// ...` `})`
遥想当年,实例化后的 bus 不知放哪好,最后无奈将其放到了 window 下,一直 window.bus 的使用。虽然这样也没问题,但仍是影响到了全局做用域。函数
忽然的某一天,我发现能够挂载在 vue 的根实例下(今后告别 window.bus),因而便有了:this
`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,那么它们是响应同步的。.net
`var` `bus =` `new` `Vue({` `data: {` `count: 0` `}` `})`
以上,子组件 a 修改了 count,若是子组件 b 有用到 count,那么它就能响应到最新 count 的值。prototype
说了这么多,你还没发现吗?这个不就是实现了非组件之间通讯,vuex 的 state 吗?!code
封装 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` `}` 欢迎加入全栈开发交流划水交流圈:582735936 面向划水1-3年前端人员 帮助突破划水瓶颈,提高思惟能力 `})` `// 子组件 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 步骤上面已经有了,第 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)` `}` 欢迎加入全栈开发交流划水交流圈:582735936 面向划水1-3年前端人员 帮助突破划水瓶颈,提高思惟能力 `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,从而实现了非父子组件之间的响应同步。所有源码参考这里 。