详解Vuex下Store的模块化拆分实践


Posted in Javascript onJuly 31, 2019

前言

最近的项目用到了 vue.js + vuex + vue-router 全家桶,版本为 >2.0,在搞Store的时候发现,圈子里大部分关于vuex的文章都是比较基础的Demo搭建方式,很少有涉及到比较复杂的模块化拆分的Store实践,而且事实上也有朋友在实践中问到过这方面的内容,vuex自身提供了模块化的方式,因此在这里总结一下我自己在项目里的心得。

模块化拆分

vue.js的项目文件结构在这里就不说了,大家可以通过vue-cli初始化项目,脚手架会为你搭建一个start项目的最佳实践。

默认你已经搭架好了一个项目,而且需要建立或者已经是一个复杂的Store,但是还没有进行模块拆分,你可以尝试对其进行模块拆分,当然在一开始你不必一定需要这么做。

1. 安装Vuex,建立文件结构

在项目根目录下安装vuex:

npm install vuex -S

安装完毕后,在项目的src文件夹下新建一个store文件夹,并且分别在其中新建modules,actions,mutations,getters,constants子文件夹和一个index.js文件。

目录结构如下:

└─ demo/
  ├── build/
  ├── config/
  ├── node_modules/
  ├── src/
  │  ├── assets/
  │  ├── components/
  │  ├── store/
  │  │  ├── actions/ 
  │  │  │  ├──aAction.js
  │  │  │  ├──bAction.js
  │  │  │  └──cAction.js
  │  │  ├── constants/
  │  │  │  └── types.js
  │  │  ├── getters/
  │  │  │  └── aGetter.js
  │  │  ├── modules/
  │  │  │  ├── aModules.js
  │  │  │  ├── bModules.js
  │  │  │  ├── cModules.js
  │  │  │  └── index.js
  │  │  ├── mutations/
  │  │  │  ├── aMutation.js
  │  │  │  ├── bMutation.js
  │  │  │  └── cMutation.js
  │  │  └── index.js
  │  ├── App.vue
  │  └── main.js
  ├── static/
  ├── utils/
  ├── test/
  └── index.html

好了,基本的文件结构大概就是上面?这样的。

2. 编写模块A

在编写模块之前,首先设定一些type类,例如:

types.js

module.exports = keyMirror({

  FETCH_LIST_REQUEST: null,
  FETCH_LIST_SUCCESS: null,
  FETCH_LISR_FAILURE: null
  
})

function keyMirror (obj) {
 if (obj instanceof Object) {
  var _obj = Object.assign({}, obj)
  var _keyArray = Object.keys(obj)
  _keyArray.forEach(key => _obj[key] = key)
  return _obj
 }
}

上面自己实现keyMirror的方法,大家也可以使用下面这个包:

https://github.com/STRML/keyMirror

keyMirror的作用就是下面这个一个形式?,作用其实也不是很大:

Input: {key1: null, key2: null}

Output: {key1: key1, key2: key2}

actions/aAction.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'

export const fetchListAction = {
  fetchList ({ commit, state }, param) {
    commit(FETCH_LIST_REQUEST)
    axios.get('http://youdomain.com/list')
     .then(function (response) {
      commit(FETCH_LIST_SUCCESS, {
        data: response.data
      }) 
      console.log(response);
     })
     .catch(function (error) {
      commit(FETCH_LIST_FAILURE, {
        error: error
      })
      console.log(error);
     });
  }
}

getters/aGetter.js

export const = fetchListGetter = {
  hotList (state) {
    return state.list.data.slice(0, 10)
  }
}

mutations/aMutation.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'

export const fetchListMutation = {
  [FETCH_LIST_REQUEST] (state) {
    state.isFetching = true
  },
  [FETCH_LIST_SUCCESS] (state, action) {
    state.isFetching = false
    state.data = action.data
    state.lastUpdated = (new Date()).getTime()
  },
  [FETCH_LIST_FAILURE] (state, action) {
    state.isFetching = false
    state.error = action.error
  }
}

modules/aModule.js

import { fetchListAction } from '../actions/aAction'
import { fetchListGetter } from '../getters/aGetter'
import { fetchListMutation } from '../mutations/aMutation'

export const list = {
  state: {
    isFetching: false,
    data: []
  }
  actions: fetchListAction,
  getters: fetchListGetter,
  mutations: fetchListMutation
}

modules/index.js

import { list } from './aModule'

module.exports = {
  list: list
}

3. 挂载store

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import { list } from './modules'

Vue.use(Vuex)

const store = new Vuex.Store({
 modules: {
  list: list
  
 },
 plugins: [createLogger()],
 strict: process.env.NODE_ENV !== 'production'
})

if (module.hot) {
 module.hot.accept(['./mutations'], () => {
  const newMutations = require('./mutations').default

  store.hotUpdate({
   mutations: newMutations
  })
 })
}

export default store

4. store注入vue实例

main.js

····
import store from './store'

 ···· 


var vue = new Vue({
 store,
 
 ···· 

})

vue.$mount('#app')

5. 在Component中使用

Vuex 提供了组件中使用的mapState,mapAction,mapGetter方法,因此可以很方便的调用。

Example.vue

<template>

 ·········

</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
  ·······
  methods: {
    ...mapActions([
      'fetchList'
    ])
  },
  computed: {
    ...mapState{
      list: state => state.list
    },
    ...mapGetters{[
      'hotList'
    ]}
  }
}
</script>
<style>
  ·······
</style>

复用模块

模块化拆分之后可以实现较为复杂的数据流,特别地,如果对action和mutation稍加改造,就可以复用模块:
比如我们在Example.vue中发起Action:

Example.vue

<template>

 ·········

</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
  ·······
  mounted () {
    this.fetchList({
      request: 'week'
    })
  },
  methods: {
    ...mapActions([
      'fetchList'
    ])
  },
  computed: {
    ...mapState{
      list: state => state.list
    },
    ...mapGetters{[
      'hotList'
    ]}
  }
}
</script>
<style>
  ·······
</style>

在上面的例子中,我们在组件挂载完成之后发起了一个fetchList的action,并添加了一个名为request的参数,这里给一个week值,也可以给按照业务需要给month、year之类的值,接下来对aAction.js做一些修改。

actions/aAction.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'

export const fetchListAction = {
  fetchList ({ commit, state }, param) {
    commit(FETCH_LIST_REQUEST, {
      request: param['request']
    })
    axios.get(`http://youdomain.com/${param['request']}list`)
     .then(function (response) {
      commit(FETCH_LIST_SUCCESS, {
        request: param['request']
        data: response.data
      }) 
      console.log(response);
     })
     .catch(function (error) {
      commit(FETCH_LIST_FAILURE, {
        request: param['request']
        error: error
      })
      console.log(error);
     });
  }
}

请求成功之后,在 commit()中加入了一个request的参数,这样Mutation就可以从里面获取相应的参数,最后对aMutation做一些修改。

mutations/aMutation.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'

export const fetchListMutation = {
  [FETCH_LIST_REQUEST] (state, action) {
    state[action.request].isFetching = true
  },
  [FETCH_LIST_SUCCESS] (state, action) {
    state[action.request].isFetching = false
    state[action.request].data = action.data
    state[action.request].lastUpdated = (new Date()).getTime()
  },
  [FETCH_LIST_FAILURE] (state, action) {
    state[action.request].isFetching = false
    state[action.request].error = action.error
  }
}

state加入了[action.request],以区分不同的接口数据。

完成以上修改后,只需要在组件调用相应的action时加入不同的参数,就可以调用相同类型但数据不同的接口。

总结

以上是我在Vuex实践中总结的一些东西,分享给大家,如果有不合理或者错误❌的地方,也希望各位老司机不吝赐教,有机会多交流。也希望大家多多支持三水点靠木。

微信号:pasturn
Github:https://github.com/pasturn

Javascript 相关文章推荐
了解jQuery技巧来提高你的代码
Jan 08 Javascript
js中将URL中的参数提取出来作为对象的实现代码
Aug 16 Javascript
JavaScript SetInterval与setTimeout使用方法详解
Nov 15 Javascript
js实现带缓冲效果的仿QQ面板折叠菜单代码
Sep 06 Javascript
js调用父框架函数与弹窗调用父页面函数的简单方法
Nov 01 Javascript
jQuery的事件预绑定
Dec 05 Javascript
Bootstrap CSS布局之列表
Dec 15 Javascript
详解Javascript中DOM的范围
Feb 13 Javascript
js实现一键复制功能
Mar 16 Javascript
使用 Node.js 对文本内容分词和关键词抽取
May 27 Javascript
浅谈vue项目4rs vue-router上线后history模式遇到的坑
Sep 27 Javascript
使用vue for时为什么要key【推荐】
Jul 11 Javascript
ES6 Iterator接口和for...of循环用法分析
Jul 31 #Javascript
Vuex 模块化使用详解
Jul 31 #Javascript
判断“命令按钮”是否被鼠标单击详解
Jul 31 #Javascript
express框架下使用session的方法
Jul 31 #Javascript
ES6中异步对象Promise用法详解
Jul 31 #Javascript
JS实现在线ps功能详解
Jul 31 #Javascript
ES6中定义类和对象的方法示例
Jul 31 #Javascript
You might like
PHP 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
PHP 字符串长度判断效率更高的方法
2014/03/02 PHP
JavaScript插入动态样式实现代码
2012/02/22 Javascript
Javascript算符的优先级介绍
2013/03/20 Javascript
jQuery实现炫酷的鼠标轨迹特效
2015/02/01 Javascript
简单掌握JavaScript中const声明常量与变量的用法
2016/05/21 Javascript
Js删除数组中某一项或几项的几种方法(推荐)
2016/07/27 Javascript
jQuery实现弹窗下底部页面禁止滑动效果
2017/12/19 jQuery
Angular5中调用第三方库及jQuery的添加的方法
2018/06/07 jQuery
JQuery Ajax执行跨域请求数据的解决方案
2018/12/10 jQuery
javascript中如何判断类型汇总
2019/05/14 Javascript
vue项目前端错误收集之sentry教程详解
2019/05/27 Javascript
JS简易计算器实例讲解
2020/06/30 Javascript
[03:59]5分钟带你了解什么是DOTA2(第二期)
2017/02/07 DOTA
[01:42:49]DOTA2-DPC中国联赛 正赛 iG vs PSG.LGD BO3 第一场 2月26日
2021/03/11 DOTA
介绍Python的@property装饰器的用法
2015/04/28 Python
在Python中使用base64模块处理字符编码的教程
2015/04/28 Python
Pyhton中单行和多行注释的使用方法及规范
2016/10/11 Python
python多行字符串拼接使用小括号的方法
2020/03/19 Python
Python中函数参数调用方式分析
2018/08/09 Python
python去除拼音声调字母,替换为字母的方法
2018/11/28 Python
使用python绘制二元函数图像的实例
2019/02/12 Python
python使用Plotly绘图工具绘制气泡图
2019/04/01 Python
Python-copy()与deepcopy()区别详解
2019/07/12 Python
react+django清除浏览器缓存的几种方法小结
2019/07/17 Python
将自己的数据集制作成TFRecord格式教程
2020/02/17 Python
ABOUT YOU罗马尼亚:超过600个时尚品牌
2019/09/19 全球购物
方正Java笔试题
2014/07/03 面试题
财务人员个人求职信范文
2013/12/04 职场文书
办理收楼委托书范本
2014/10/09 职场文书
2014年超市工作总结
2014/11/19 职场文书
干货干货!2019最新优秀创业计划书
2019/03/21 职场文书
2019下半年英语教师的教学工作计划(3篇)
2019/09/25 职场文书
解决Jupyter-notebook不弹出默认浏览器的问题
2021/03/30 Python
vue实现列表拖拽排序的示例代码
2022/04/08 Vue.js
使用Postman测试需要授权的接口问题
2022/06/21 Java/Android