vuex状态初始化中间件设计

总算把最近尝试的东西实现出来了,写点文章沉淀一下。javascript

前言

单页面应用在使用单向数据流的设计方案后,状态树的控制就变得相当重要。这里面对的问题在于一个最基础的点,同时也是最经常使用的一点 -- 初始状态的控制与恢复
每次切换到一个页面,若是是动态数据页面,老是会先加载一些默认数据,或者清空现有数据,换句话说,就是初始化一下。
在以前使用vue + vuex的过程当中,对于状态初始化的设计思路,是将其放到一个全局服务中,这样每次进到不一样页面,只须要调用同一个全局的动做,就能完成初始化。同时,具体的初始化状态值,则由每一个模块本身控制。
vuex init design前端

问题

在查看了vuex源码后,发现对于vuex的module而言,只是将全部module放到了同一个vm对象中,而后watch了一下。笔者以前在申明module中state对象时,常常使用const关键字,用意是认为申明时的state值一直做为静态值存在着,表明可返回的初始状态。而看了源码后,被打脸打飞了。。。。
那么怎么才能有一个静态的初始状态,让咱们在切换页面时可以恢复呢?固然,最好这个初始状态时可以根据状况,可更替的。换句话说,这个所谓初始状态,应该是一个可定义的用于恢复的静态状态。vue

解决方案

Talk is cheap, show me the code.java

来来来,一言不合就上代码~
源码以及相关样例能够在个人github上找到,连接点此git

import Vue from 'vue'

function deepClone(obj) {
  if (Array.isArray(obj)) {
    return obj.map(deepClone)
  } else if (obj && typeof obj === 'object') {
    var cloned = {}
    var keys = Object.keys(obj)
    for (var i = 0, l = keys.length; i < l; i++) {
      var key = keys[i]
      cloned[key] = deepClone(obj[key])
    }
    return cloned
  } else {
    return obj
  }
}

const commonMutations = {
  INIT_STATE(state, moduleName) {
    state[moduleName] = deepClone(state.cache[moduleName])
  },
  CACHE_STATE(state, moduleName, newState) {
    state.cache[moduleName] = deepClone(newState)
  },
}

const commonActions = {
  initComponent({ dispatch }, name) {
    dispatch('INIT_STATE', name)
  },
  changeCacheState(store, module, state = store._vm[module]) {
    store.dispatch('CACHE_STATE', module, state)
  }
}

export default {
  onInit(state, store) {
    // hot load common mutations
    store.hotUpdate({
      mutations: commonMutations
    })
    // cache init state
    store._setupModuleState(state, {
        cache: {
          state: deepClone(state)
        }
      })
      // mixin all actions to the root vm
    Vue.mixin({
      vuex: {
        actions: commonActions
      }
    })
  }
}

关键点解读

1. 深层克隆

这里deep copy用了vuex源码里util的一个方法,官方注释上写着说比JSON.parse(JSON.stringify(obj))要来的更快,因而我就参(fu)考(zhi)过来了~~
什么?为何要深拷贝?由于咱们要维护一个静态状态的前端临时仓库呀~就像是前端的临时数据库同样,所谓数据驱动嘛~
因而下一步就是咱们怎么把这个临时的静态状态对象让全局可以共享。这里用的方法就是一块儿扔到store绑定的vm对象上去github

2. 全局使用便捷性

为了可以让代码全局都享受到这个便捷性,笔者在这里利用了vuex的中间件。vuex的中间件有2个特色,首先它提供了init与mutate动做的切入口。其次是它与store有着紧密联系。也所以,能够知足咱们便捷性须要用到的2个需求:vuex

  1. 应用启动时注册数据库

  2. 应用全局可调用,不须要另外引入spa

因此就将init须要用到的commonMutation经过hotupdate的方式,在module初始化的时候,将init模块注册到全局,同时在store中加上当前模块初始状态的深拷贝
此外,利用了vue自己的mixin机制,将commonActions注册到全局的vm对象上
这样作的结果是什么呢?
去看看demo吧~~
地址在此设计

相关文章
相关标签/搜索