Vuex的学习及使用

解决多个组件的状态共享,解决路由间传递复杂数据,便于维护。

目录结构

通常情况下 我们在src下建立一个store文件夹 具体如下图

  • state.js里是要用到的状态;
  • getters.js是用来映射state里的状态;
  • mutations.js是改变state里状态的一些方法,只能同步操作;
  • mutations-types.js是统一管理mutaions方法名的一个文件(多人协作时方便管理,也可以不用);
  • actions.js 不直接改变state里的状态,通过commit mutations里的方法进行改变state,并且可以分发多个mutaitons并且可以进行异步操作;
  • index.js 入口文件
例子:

例子中用了export,export default 两种不同的导出语法

如果不清楚可以查阅另一篇文章 ✌ 点击进入 javascript的模块化

state.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const state = {
singer: {},
playing: false,
fullScreen: false,
playList: [],
sequenceList: [],
currentIndex: -1,
//歌单详细列表
disc: {},
// 排行列表
topList: {},
}

export default state

getters.js (进行映射state)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const singer = state => state.singer

export const playing = state => state.playing

export const fullScreen = state => state.fullScreen

export const playList = state => state.playList

export const sequenceList = state => state.sequenceList

export const currentIndex = state => state.currentIndex

export const disc = state => state.disc

export const topList = state => state.topList

mutations-types.js (统一管理mutations方法名称常量)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const SET_SINGER = 'SET_SINGER'

export const SET_PLAYING_STATE = 'SET_PLAYING_STATE'

export const SET_FULL_SCREEN = 'SET_FULL_SCREEN'

export const SET_PLAYLIST = 'SET_PLAYLIST'

export const SET_SEQUENCE_LIST = 'SET_SEQUENCE_LIST'

export const SET_CURRENT_INDEX = 'SET_CURRENT_INDEX'

export const SET_DISC = 'SET_DISC'

export const SET_TOP_LIST = 'SET_TOP_LIST'

mutations.js (改变state的一些方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import * as types from './mutations-types'

const mutations = {
[types.SET_SINGER] (state, singer) {
state.singer = singer
},
[types.SET_PLAYING_STATE](state, flag) {
state.playing = flag
},
[types.SET_FULL_SCREEN](state, flag) {
state.fullScreen = flag
},
[types.SET_PLAYLIST](state, list) {
state.playList = list
},
[types.SET_SEQUENCE_LIST](state, list) {
state.sequenceList = list
},
[types.SET_CURRENT_INDEX](state, index) {
state.currentIndex = index
},
[types.SET_DISC](state, disc) {
state.disc = disc
},
[types.SET_TOP_LIST](state, topList) {
state.topList = topList
}
}

export default mutations

actions.js(派发多个mutations或进行异步操作)

在 store 上注册 action。处理函数总是接受 context 作为第一个参数,payload 作为第二个参数(可选)。

context包含以下属性,第二个参数可选(调用时传入的参数)

1
2
3
4
5
6
7
8
{
state, // 等同于 `store.state`,若在模块中则为局部状态
rootState, // 等同于 `store.state`,只存在于模块中
commit, // 等同于 `store.commit`
dispatch, // 等同于 `store.dispatch`
getters, // 等同于 `store.getters`
rootGetters // 等同于 `store.getters`,只存在于模块中
}

下面用了结构赋值 第一个参数只接收commit,有些场景也需要接收state {commit, state}

1
2
3
4
5
6
7
8
import * as types from './mutations-types'
// 清空播放列表
export const deleteSongLits = function({commit}, val) {
commit(types.SET_PLAYLIST, [])
commit(types.SET_SEQUENCE_LIST, [])
commit(types.SET_CURRENT_INDEX, -1)
commit(types.SET_PLAYING_STATE, false)
}

index.js (vuex入口文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import state from './state'
import mutations from './mutations'
// 内置的logger插件 日志插件可以在控制台查看vuex的信息进行调试
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)
// run dev时 debug为true
const debug = process.env.NODE_EN !== 'production'
export default new Vuex.Store({
actions,
getters,
state,
mutations,
// strict 严格模式 true为开启
// 任何 mutation 处理函数以外修改 Vuex state 都会抛出错误
strict: debug,
plugins: debug ? [createLogger()] : []
})
在项目的入口文件main.js中将该 Store 实例添加到构造的 Vue 实例中

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue'
import App from './App'
import router from './router'
import fastclick from 'fastclick'
import 'babel-polyfill'
import 'common/stylus/index.styl'
import VueLazyLoad from 'vue-lazyload'
import store from './store' // 引入store
Vue.config.productionTip = false

fastclick.attach(document.body)
Vue.use(VueLazyLoad, {
loading: require('common/image/logo@2x.png')
})

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,// 添加到Vue实例中
render: h => h(App)
})

利用辅助函数在组件中获取state,映射getter,提交mutation,分发action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { mapState, mapMutations, mapActions } from 'vuex'

export default {
computed: {
...mapState([
// 映射 this.singer 为 store.state.singer
'singer'
]),
// 把 `this.playing` 映射为 `this.$store.getters.playing`
...mapGetters(['playing'])
},
methods: {
...mapMutations([
'SET_SINGER', // 将 `this.SET_SINGER()` 映射为 `this.$store.commit('SET_SINGER')`

// `mapMutations` 也支持载荷:
'SET_SINGER' // 将 `this.SET_SINGER(amount)` 映射为 `this.$store.commit('SET_SINGER', amount)`
]),
...mapMutations({
setSinger: 'SET_SINGER' // 将 `this.setSinger()` 映射为 `this.$store.commit('SET_SINGER')`
})
...mapActions([
'deleteSongLits', // 将 `this.deleteSongLits()` 映射为 `this.$store.dispatch('deleteSongLits')`

// `mapActions` 也支持载荷:
// 'deleteSongLits' // 将 `this.deleteSongLits(amount)` 映射为 `this.$store.dispatch('deleteSongLits', amount)`
]),
...mapActions({
empty: 'deleteSongLits' // 将 `this.empty()` 映射为 `this.$store.dispatch('deleteSongLits')`
})
}
}

vuex的分割模块

vue-element-admin的store为例 ✌ 点击传送

目录结构:
  • index.js 入口文件
  • getter.js state的映射
  • modules模块文件夹,里面为一个个vuex模块

以errorLog模块为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const errorLog = {
state: {
logs: []
},
mutations: {
ADD_ERROR_LOG: (state, log) => {
state.logs.push(log)
}
},
actions: {
addErrorLog({ commit }, log) {
commit('ADD_ERROR_LOG', log)
}
}
}

export default errorLog
// 导出一个对象 有sate, mutations, actions的对象

getter.js state的映射

1
2
3
4
const getters = {
errorLogs: state => state.errorLog.logs
}
export default getters

index.js vuex入口文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import errorLog from './modules/errorLog'
import permission from './modules/permission'
import tagsView from './modules/tagsView'
import user from './modules/user'
import getters from './getters'
// 加载每一个模块
Vue.use(Vuex)

const store = new Vuex.Store({
// 注入modules对象中
modules: {
app,
errorLog,
permission,
tagsView,
user
},
getters
})

export default store

main.js 项目入口文件

1
2
3
4
5
6
7
8
9
10
import store from './store' // 加载store

new Vue({
el: '#app',
router,
store, // 挂在到Vue实例
i18n,
template: '<App/>',
components: { App }
})

模块写法只是将state,mutations,actions写到了不同的功能模块中,并且分别加载并挂在到Vuex实例中,多人写作或者功能模块较多的项目推荐这种写法

Vuex数据持久化,结合localStorage

vuex刷新后就会消失, 很多应用场景刷新要保留数据

结合本地存储只要不手动清除,就一直存在

思路

  • 最好是写一个js文件,根据业务场景写localStorage的set和get和移除或清空
  • state里的数据直接获取localStorage存储的数据
  • mutaions或actions方法里调用js文件中是set get 移除 清空等方法

demo

写set get方法的文件

cache.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import storage from 'good-storage'
const SEARCH_KEY = '__search__'
const SEARCH_MAX_LENGTH = 15

// 保存搜索历史
export function saveSearch(query) {
// 本地存储数组
let searches = storage.get(SEARCH_KEY, [])
// 进行比较后插入
insertArray(searches, query, (item) => {
return item === query
}, SEARCH_MAX_LENGTH)
// 保存
storage.set(SEARCH_KEY, searches)
return searches
}

export function loadSearch() {
return storage.get(SEARCH_KEY, [])
}

// 删除一个
export function deleteSearch(query) {
let searches = storage.get(SEARCH_KEY, [])
deleteFromArray(searches, (item) => {
return item === query
})
storage.set(SEARCH_KEY, searches)
return searches
}

export function clearSearch() {
storage.remove(SEARCH_KEY)
return []
}

state.js (获取存储)

1
2
3
4
5
6
7
8

import {loadSearch} from 'common/js/cache'

const state = {
// 搜索历史
searchHistory: loadSearch(),
}
export default state

mutations.js

1
2
3
4
5
6
7
8
9
10
import * as types from './mutations-types'

const mutations = {

[types.SET_SEARCH_HISTORY](state, history) {
state.searchHistory = history
}
}

export default mutations

actions.js (更新存储)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import * as types from './mutations-types'
import {saveSearch, deleteSearch, clearSearch,} from 'common/js/cache'

// 搜索历史相关
export const saveSearchHistory = function({commit}, query) {
commit(types.SET_SEARCH_HISTORY, saveSearch(query))
}

export const deleteSearchHistory = function({commit}, query) {
commit(types.SET_SEARCH_HISTORY, deleteSearch(query))
}

export const clearSearchHistory = function({commit}) {
commit(types.SET_SEARCH_HISTORY, clearSearch())
}

当派发actions时会做对应的存储操作,state会拿到本地存储的数据

------ 本文结束------
0%