2025-03-29 16:55:07 +08:00

447 lines
10 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# vuex
## 介绍
专为 Vue.js 应用程序开发的**状态管理模式**, 采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
https://vuex.vuejs.org/zh/
![image-20210127204118836|788x443](https://img.081024.xyz/image-20210127204118836.png)
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 子模块