447 lines
10 KiB
Markdown
Executable File
447 lines
10 KiB
Markdown
Executable File
# vuex
|
||
|
||
## 介绍
|
||
|
||
专为 Vue.js 应用程序开发的**状态管理模式**, 采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
|
||
|
||
https://vuex.vuejs.org/zh/
|
||
|
||

|
||
|
||
1. 修改state状态必须通过 **`mutations`**
|
||
2. **`mutations`** 只能执行**同步**代码,类似 ajax、定时器之类的代码不能在mutations中执行
|
||
3. 执行**异步**代码,要通过 **`actions`** ,然后将数据提交给 `mutations` 才可以完成
|
||
4. state 的状态即共享数据可以在组件中引用
|
||
5. 组件中可以调用 action / mutations
|
||
|
||
## 使用场景
|
||
|
||
不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。如果您的应用够简单,您最好不要使用 Vuex
|
||
|
||
## 下载 安装
|
||
|
||
```bash
|
||
npm install vuex --save
|
||
```
|
||
|
||
```js
|
||
import Vue from 'vue'
|
||
import Vuex from 'vuex'
|
||
Vue.use(vuex)
|
||
const store = new Vuex.Store({})
|
||
new Vue({
|
||
el: '#app',
|
||
store
|
||
})
|
||
```
|
||
|
||
==Vuex有五个最重要的构造器: state, mutations, actions, getters, modules==
|
||
|
||
## state
|
||
|
||
> state是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state对象中
|
||
|
||
几种使用方法:
|
||
|
||
### 原始调用
|
||
|
||
组件中可以使用 **this.$store** 获取到vuex中的store对象实例
|
||
|
||
```html
|
||
<div> state的数据:{{ $store.state.count }}</div>
|
||
```
|
||
|
||
### 结合计算属性
|
||
|
||
将state属性定义在计算属性中
|
||
|
||
```js
|
||
computed: {
|
||
count () {
|
||
return this.$store.state.count
|
||
}
|
||
}
|
||
```
|
||
|
||
### 辅助函数 mapState
|
||
|
||
> 方便获取多个状态, 像前面在 computed 里多次定义太啰嗦
|
||
|
||
```js
|
||
// 第一步:导入mapState
|
||
import { mapState } from 'vuex'
|
||
// 第二步:采用数组形式引入state属性
|
||
// 第三步:mapState函数返回的是对象, 利用展开运算符合并到计算属性里
|
||
computed: {
|
||
...mapState([
|
||
'count',
|
||
'count2',
|
||
//...
|
||
])
|
||
}
|
||
|
||
// 如果计算属性的名称和state的子节点名称不同
|
||
computed: {
|
||
...mapState({coutAlias: state => state.cout}),
|
||
}
|
||
|
||
// 使用
|
||
<div> state的数据:{{ count }}</div>
|
||
```
|
||
|
||
## getters
|
||
|
||
> 除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到 getters
|
||
> 可以认为是 store 的计算属性
|
||
|
||
例如,state中定义了list,为1-10的数组,组件中,需要显示所有大于5的数据
|
||
|
||
```js
|
||
state: {
|
||
list: [1,2,3,4,5,6,7,8,9,10]
|
||
},
|
||
getters: {
|
||
// getters函数的第一个参数是 state
|
||
// 必须要有返回值
|
||
filterList: state => state.list.filter(item => item > 5)
|
||
}
|
||
```
|
||
|
||
===通过属性访问时会进行缓存===
|
||
|
||
getter 可以返回一个函数, 实现向 getter 传参
|
||
|
||
```js
|
||
state: {
|
||
list: [1,2,3,4,5,6,7,8,9,10]
|
||
},
|
||
getters: {
|
||
// getters函数的第一个参数是 state
|
||
// 必须要有返回值
|
||
filterList: state => (n)=>state.list.filter(item => item > n)
|
||
}
|
||
```
|
||
|
||
===通过函数每次都进行调用不会缓存===
|
||
|
||
### 原始调用
|
||
|
||
```vue
|
||
<div>{{ $store.getters.filterList }}</div>
|
||
```
|
||
|
||
```vue
|
||
<div>{{ $store.getters.filterList(5) }}</div>
|
||
```
|
||
|
||
### 结合 computed
|
||
|
||
```js
|
||
computed: {
|
||
filterList () {
|
||
return this.$store.getters.filterList
|
||
}
|
||
}
|
||
```
|
||
|
||
### 辅助函数 mapGetters
|
||
|
||
```js
|
||
computed: {
|
||
...mapGetters(['filterList'])
|
||
}
|
||
|
||
// 重命名
|
||
computed: {
|
||
...mapGetters({filterListAlias:'filterList'})
|
||
}
|
||
|
||
// ...
|
||
<div>{{ filterList }}</div>
|
||
```
|
||
|
||
## mutations
|
||
|
||
> state数据的修改只能通过mutations,并且mutations必须是同步更新, 不能写异步代码 (比如axios)
|
||
|
||
mutations是一个对象,对象中存放修改state的方法
|
||
|
||
```js
|
||
mutations: {
|
||
// 方法里参数 第一个参数是当前store的state属性
|
||
// 第二个可选参数payload, 载荷 运输参数, 外部调用mutaiions的时候可以传递参数
|
||
addCount (state, data) {
|
||
state.count += data
|
||
}
|
||
},
|
||
```
|
||
|
||
### this.$store.commit
|
||
|
||
```js
|
||
// 调用方法
|
||
//...
|
||
<button @click="addCount(666)">+</button>
|
||
|
||
//...
|
||
methods: {
|
||
addCount(num){
|
||
this.$store.commit('addCount', num) // commit 提交
|
||
}
|
||
}
|
||
```
|
||
|
||
### mapMutations
|
||
|
||
> mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入
|
||
|
||
```js
|
||
import { mapMutations } from 'vuex'
|
||
methods: {
|
||
...mapMutations(['addCount']),
|
||
}
|
||
// 对像写法, 重命名
|
||
methods: {
|
||
...mapMutations({changeAllDistrictAlias:'changeAllDistrict'})
|
||
}
|
||
```
|
||
|
||
## actions
|
||
|
||
> state是存放数据的,mutations是同步更新数据,actions则负责进行异步操作(比如请求, 定时器)
|
||
|
||
```js
|
||
// 定义actions
|
||
actions: {
|
||
// 第一个参数context表示当前的store的实例,可以通过 context.state 获取状态,也可以通过context.commit 来提交mutations,也可以 context.dispatch调用其他的action
|
||
// 第二个参数data 可选
|
||
getAsyncCount (context) { // 这里可以用解构 getAsyncCount({ commit })
|
||
setTimeout(function(){
|
||
context.commit('addCount', 123) // 对应的可以简写 commit('addCount', 123)
|
||
}, 1000)
|
||
},
|
||
|
||
// 写法2
|
||
getAsyncCount ({commit}) {
|
||
setTimeout(function(){
|
||
commit('addCount', 123)
|
||
}, 1000)
|
||
},
|
||
|
||
}
|
||
```
|
||
|
||
### 原始调用
|
||
|
||
```js
|
||
addAsyncCount () {
|
||
this.$store.dispatch('getAsyncCount') // dispatch 委派
|
||
}
|
||
```
|
||
|
||
```js
|
||
// 传参
|
||
addAsyncCount () {
|
||
this.$store.dispatch('getAsyncCount', 123)
|
||
}
|
||
```
|
||
|
||
### mapActions
|
||
|
||
> actions也有辅助函数,可以将action导入到组件中
|
||
|
||
```js
|
||
import { mapActions } from 'vuex'
|
||
methods: {
|
||
...mapActions(['getAsyncCount'])
|
||
}
|
||
|
||
// 重命名
|
||
methods: {
|
||
...mapActions({ initialDistrictAlias: 'initialDistrict' })
|
||
}
|
||
```
|
||
|
||
直接通过 this.方法就可以调用
|
||
|
||
```vue
|
||
<button @click="getAsyncCount(111)">+异步</button>
|
||
```
|
||
|
||
## Module
|
||
|
||
> 每个子模块都是一个对象, 可以自己拥有state, mutations, actions, getters
|
||
|
||
```js
|
||
const store = new Vuex.Store({
|
||
modules: {
|
||
user: {
|
||
state: {
|
||
token: '12345'
|
||
}
|
||
},
|
||
setting: {
|
||
state: {
|
||
name: 'Vuex实例'
|
||
}
|
||
}
|
||
})
|
||
```
|
||
|
||
### 原始调用
|
||
|
||
```vue
|
||
// store.state.模块名.字段名
|
||
<template>
|
||
<div>
|
||
<div>用户token {{ $store.state.user.token }}</div>
|
||
<div>网站名称 {{ $store.state.setting.name }}</div>
|
||
</div>
|
||
</template>
|
||
```
|
||
|
||
### 配合 getters + mapGetters
|
||
|
||
```js
|
||
// 配合getters简写
|
||
getters: {
|
||
token: state => state.user.token,
|
||
name: state => state.setting.name
|
||
}
|
||
|
||
// 再配合mapGetters
|
||
computed: {
|
||
...mapGetters(['token', 'name'])
|
||
}
|
||
```
|
||
|
||
### 命名空间
|
||
|
||
==注意: 默认情况下,模块内部的 action、mutation 和 getter 是注册在**全局命名空间**的==(简单的说不加模块名直接带上字段名就可以调用 state.token) , 为了保证内部模块的高封闭性,采用namespaced来进行设置
|
||
|
||
```js
|
||
user: {
|
||
namespaced: true, // 命名空间
|
||
state: {
|
||
token: '12345'
|
||
},
|
||
mutations: {
|
||
// 这里的state表示的是user的state
|
||
updateToken (state) {
|
||
state.token = 678910
|
||
}
|
||
}
|
||
},
|
||
```
|
||
|
||
方案1:**带上模块的属性名路径**
|
||
|
||
```js
|
||
// 对于有命名空间的action和mutation, 要带上 '命名空间/模块名'
|
||
methods: {
|
||
...mapMutations(['user/updateToken']),
|
||
test () {
|
||
this['user/updateToken']()
|
||
}
|
||
}
|
||
<button @click="test">修改token</button>
|
||
```
|
||
|
||
```js
|
||
// 调用模块里的mutatios/actions
|
||
this.$store.dispatch('user/getUserInfo')
|
||
this.$store.commit('user/getUserInfo')
|
||
```
|
||
|
||
```js
|
||
computed: {
|
||
// 把模块名字符串当成第一个参数传进去
|
||
...mapState('some/nested/module', {
|
||
a: state => state.a,
|
||
b: state => state.b
|
||
})
|
||
},
|
||
methods: {
|
||
...mapActions('some/nested/module', [
|
||
'foo',
|
||
'bar'
|
||
])
|
||
}
|
||
```
|
||
|
||
方案2: **createNamespacedHelpers** 创建基于某个命名空间辅助函数
|
||
|
||
```js
|
||
import { mapGetters, createNamespacedHelpers } from 'vuex'
|
||
// ...
|
||
const { mapMutations: mapMutationsUser } = createNamespacedHelpers('user') //创建出属于当前模块的辅助函数, 是一个对象, 里面包括mapGetters, mapState, mapMutations
|
||
// 解构并重命名
|
||
export default {
|
||
computed: {
|
||
...mapGetters(['token', 'appName']) // 这里就是子模块里的
|
||
},
|
||
methods: {
|
||
...mapMutationsUser(['setUserInfo'])
|
||
}
|
||
}
|
||
<button @click="updateToken">修改token2</button>
|
||
```
|
||
|
||
## 持久化
|
||
|
||
`VuexPersistence`
|
||
|
||
https://www.npmjs.com/package/vuex-persist
|
||
|
||
https://www.cnblogs.com/lemoncool/p/9645587.html
|
||
|
||
### Steps
|
||
|
||
Import it
|
||
|
||
```
|
||
import VuexPersistence from 'vuex-persist'
|
||
```
|
||
|
||
> NOTE: In browsers, you can directly use `window.VuexPersistence`
|
||
|
||
Create an object
|
||
|
||
```js
|
||
const vuexLocal = new VuexPersistence({
|
||
storage: window.localStorage
|
||
})
|
||
```
|
||
|
||
Use it as Vue plugin.
|
||
|
||
```js
|
||
const store = {
|
||
state: { ... },
|
||
mutations: { ... },
|
||
actions: { ... },
|
||
plugins: [vuexLocal.plugin]
|
||
}
|
||
```
|
||
|
||
vuex-persist 的详细属性:
|
||
|
||
| 属性 | 类型 | 描述 |
|
||
| ------------ | ---------------------------------- | ------------------------------------------------------------ |
|
||
| key | string | 将状态存储在存储中的键。默认: 'vuex' |
|
||
| storage | Storage (Web API) | 可传localStorage, sessionStorage, localforage 或者你自定义的存储对象. 接口必须要有get和set. **默认是: window.localStorage** |
|
||
| saveState | function (key, state[, storage]) | 如果不使用存储,这个自定义函数将保存状态保存为持久性。 |
|
||
| restoreState | function (key[, storage]) => state | 如果不使用存储,这个自定义函数处理从存储中检索状态 |
|
||
| reducer | function (state) => object | 将状态减少到只需要保存的值。默认情况下,保存整个状态。 |
|
||
| filter | function (mutation) => boolean | 突变筛选。看mutation.type并返回true,只有那些你想坚持写被触发。所有突变的默认返回值为true。 |
|
||
| modules | string[] | 要持久化的模块列表。 |
|
||
|
||
## 总结
|
||
|
||
* state 仓库状态对象
|
||
* mutations 改变数据的函数, 同步
|
||
* action 异步函数
|
||
* getters 类似计算属性的数据获取
|
||
* modules 子模块
|
||
|