theme: fancy
highlight: monokai
文档:https://next.vuex.vuejs.org/zh/
提供一个Vue devtools谷歌插件安装包:https://wwe.lanzouw.com/inHnkyjawwh
一、Vuex认识
Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
二、安装和初步使用
1、安装
```bash
npm
npm install vuex@next --save
yarn
yarn add vuex@next --save ```
2、创建一个 store(仓库)
1)在根目录 ——> src ——> c(文件夹)
2)在store下创建index.js文件(这个文件提供一个初始 state 对象和一个mutation)
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { num: 111 } })
3、对这个仓库进行一个导入(在 main.js 中导入)
```javascript import { createApp } from 'vue' import App from './App.vue' import store from './store/index.js'
const app = createApp(App) app.use(store) app.mount('#app') ```
4、在页面或组件中使用
html <template> vuex <p>{{$store.state.num}}</p> </template>
三、Vuex中核心概念的使用
1、State
store本质上是一个容器,它包含着你的应用中大部分的状态。
注:对State里面的数据修改,必须要通过Mutation来进行一个提交。
1)在state中储存数据
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { num: 111 } })
2)在页面或者组件中使用
```javascript vuex
{{ $store.state.num }}
{{ num }}
```
2、mapState
1)vuex状态管理中的数据(src——>store——>index.js)
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { num: 111, name: "小明", age: 22 } })
2)在页面或者组件中使用
① 数组的方式,并且没有在当前页面定义computed属性
```vue vuex
{{$store.state.num}}
{{name}}
{{age}}
```
② 在页面还定义了其他的计算属性时,使用扩展运算符
```vue vuex
{{$store.state.num}}
{{num}}
{{name}}
{{age}}
```
③ 对象的写法(使用对象,可以自定义key)
```vue vuex
{{$store.state.num}}
{{num}}
{{name}}
{{ages}}
```
3、在setup中mapState的使用
store——>index.js里面的状态
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { num: 111, name: "小明", age: 22 } })
1)基本使用
```vue vuex
{{ $store.state.num }}
{{ num }}
{{ name }}
{{ age }}
```
2)将上面的使用封装,方便在以后使用(推荐)
① src——> hook——> useStore.js(创建这个 文件)
javascript /** * 在setup中使用mapState的封装 * @param {*} mapArr 数组 | 对象 */ import { computed } from "vue" import { useStore, mapState } from "vuex" export default function useState(mapArr) { // 获取store const store = useStore() // mapState 在 setup 中的使用(在这获取对应的函数),mapState是自己支持对象和数组的 const arrFn = mapState(mapArr) const storeState = {} // 拿到arrFn中所有的key Object.keys(arrFn).forEach(fnKey => { // 这里使用了 bind改变this指向 const fn = arrFn[fnKey].bind({ $store: store }) storeState[fnKey] = computed(fn) }) return storeState }
② 在页面使用
```vue vuex
{{ num }}
{{ name }}
{{ ages }}
```
4、getters
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
1)基本使用
① 数据源
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { name: "小明", age: 24, product: [ { name: "面包", price: 10, count: 11 }, { name: "火腿", price: 12, count: 2 }, { name: "方便面", price: 13, count: 3 }, { name: "牛奶", price: 14, count: 5 } ] }, getters: { /** * state 获取state中的数据 * getters 使用getters中其他的方法 */ totalPrice(state, getters) { let totalPrice = 0 for (let i = 0; i < state.product.length; i++) { totalPrice += state.product[i].price } return totalPrice + getters.unit }, unit() { return "元" } } })
② 在页面或者组件中使用
javascript <template> <p> getters</p> <p>{{ $store.getters.totalPrice }}</p> </template>
5、getters的返回函数(getters接受参数)
1)数据源
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { name: "小明", age: 24, product: [ { name: "面包", price: 10, count: 11 }, { name: "火腿", price: 12, count: 2 }, { name: "方便面", price: 13, count: 3 }, { name: "牛奶", price: 14, count: 5 } ] }, getters: { /** * 这样就可以在外面传入函数 */ moreThanThe(state) { return function (n) { let totalPrice = 0 for (let i = 0; i < state.product.length; i++) { if (state.product[i].count > n) continue totalPrice += state.product[i].price } return totalPrice } } } })
2)使用
vue <template> <p>{{ $store.getters.moreThanThe(4) }}</p> </template>
6、mapGetters辅助函数
1)数据源
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { name: "小明", age: 24, product: [ { name: "面包", price: 10, count: 11 }, { name: "火腿", price: 12, count: 2 }, { name: "方便面", price: 13, count: 3 }, { name: "牛奶", price: 14, count: 5 } ] }, getters: { /** * state 获取state中的数据 * getters 使用getters中其他的方法 */ totalPrice(state, getters) { let totalPrice = 0 for (let i = 0; i < state.product.length; i++) { totalPrice += state.product[i].price } return totalPrice + getters.unit }, unit() { return "元" }, /** * 这样就可以在外面传入函数 */ moreThanThe(state) { return function (n: number) { let totalPrice = 0 for (let i = 0; i < state.product.length; i++) { if (state.product[i].count > n) continue totalPrice += state.product[i].price } return totalPrice } } } })
2)使用
① 数组的使用
```vue
getters
{{ unit }}
{{ totalPrice }}
{{ nameInfo }}
```
② 对象的写法
```vue
getters
{{ unit }}
{{ totalPrice }}
{{ nameInfo }}
```
7、在setup中使用getters及mapGetters辅助函数
1)数据源
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { name: "小明", age: 24, product: [ { name: "面包", price: 10, count: 11 }, { name: "火腿", price: 12, count: 2 }, { name: "方便面", price: 13, count: 3 }, { name: "牛奶", price: 14, count: 5 } ] }, getters: { /** * state 获取state中的数据 * getters 使用getters中其他的方法 */ totalPrice(state, getters) { let totalPrice = 0 for (let i = 0; i < state.product.length; i++) { totalPrice += state.product[i].price } return totalPrice + getters.unit }, unit() { return "元" }, nameInfo(state) { return state.name } } })
2)在src——> hook——> useGetters.js 封装这个文件
javascript /** * 在setup中使用mapState的封装 * @param {*} mapArr 数组 | 对象 */ import { computed } from "vue" import { useStore, mapGetters } from "vuex" export default function useGetters(mapArr) { // 获取store const store = useStore() // mapState 在 setup 中的使用(在这获取对应的函数),mapState是自己支持对象和数组的 const arrFn = mapGetters(mapArr) const storeState = {} // 拿到arr中所有的key Object.keys(arrFn).forEach(fnKey => { // 这里使用了 bind改变this指向 const fn = arrFn[fnKey].bind({ $store: store }) storeState[fnKey] = computed(fn) }) return storeState }
3)使用
```vue
getters
{{ unit }}
{{ totalPrice }}
{{ nameInfo }}
```
8、对setup中使用辅助函数进行封装
1)封装(在src——> hook——> vuexMap.js)
javascript /** * 在setup中使用mapState的封装 * @param {*} mapArr mapState | mapGetters * @param {*} mapArr 数组 | 对象 * 注:mapState、mapState 是使用的使用传入的 */ import { computed } from "vue" import { useStore } from "vuex" export default function vuexMap(mapFun, mapArr) { // 获取store const store = useStore() // mapState 在 setup 中的使用(在这获取对应的函数),mapState是自己支持对象和数组的 const arrFn = mapFun(mapArr) const storeState = {} // 拿到arr中所有的key Object.keys(arrFn).forEach(fnKey => { // 这里使用了 bind改变this指向 const fn = arrFn[fnKey].bind({ $store: store }) storeState[fnKey] = computed(fn) }) return storeState }
2)使用
```vue
getters
{{ unit }}
{{ totalPrice }}
{{ nameInfo }}
```
9、Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
1)使用
① store ——>index.js去修改state中的数据
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { counter: 0 }, mutations: { /** * mutations修改数据源 * @param state 数据原 * @param payload 外部调用时 传入的参数 */ add(state, payload) { state.counter += payload }, reduce(state) { state.counter-- } } })
② 在页面中使用
a、常用的风格
```vue
mutation
{{$store.state.counter}}
```
b、另一种提交风格
2)将Mutation中方法封装成常量
注:Mutation中的名称 和 页面中使用的名称一样时,为了方便使用,我们可以把它定义成一个常量。
① 在store——> mutation-type.js
javascript /** * 床两一般都是大写 */ export const ADD = "add"
② 在store——> index.js
javascript import { createStore } from 'vuex' import { ADD } from "./mutation-type.js" /** * 创建仓库和导出 */ export default createStore({ state: { counter: 0 }, mutations: { /** * mutations修改数据源 * @param state 数据原 * @param payload 外部调用时 传入的参数 */ [ADD](state, payload) { state.counter += payload.num }, reduce(state) { state.counter-- } } })
③ 使用
```vue
mutation
{{$store.state.counter}}
```
10、mapMutations
1)状态管理
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { counter: 0 }, mutations: { /** * mutations修改数据源 * @param state 数据原 * @param payload 外部调用时 传入的参数 */ add(state, payload) { state.counter += payload }, reduce(state) { state.counter-- } } })
2)使用
```vue
mutation
{{$store.state.counter}}
```
11、mapMutations在setup中的使用
1)vuex中的书写
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { counter: 0 }, mutations: { /** * mutations修改数据源 * @param state 数据原 * @param payload 外部调用时 传入的参数 */ add(state, payload) { state.counter += payload }, reduce(state) { state.counter-- } } })
2)使用
```vue
mutation
{{$store.state.counter}}
```
12、Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
1)状态管理
```javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { counter: 0 }, mutations: { add(state, payload) { state.counter += payload } }, // actions 里面也是放函数的 actions: { // addActions({ commit, dispatch, state, rootGetters, rootState, getters }, payload) { // 这个式结构的写法 addActions(context, payload) { // 查看 context 的属性有哪些 console.log(context);
context.commit("add", payload)
}
}
}) ```
2)使用
```vue
action
{{$store.state.counter}}
```
13、在setup中使用mapActions
1)数据源
javascript import { createStore } from 'vuex' /** * 创建仓库和导出 */ export default createStore({ state: { counter: 0 }, mutations: { add(state, payload) { state.counter += payload } }, // actions 里面也是放函数的 actions: { // addActions({ commit, dispatch, state, rootGetters, rootState, getters }, payload) { // 这个式结构的写法 addActions(context, payload) { // 查看 context 的属性有哪些 // console.log(context); context.commit("add", payload) } } })
2)使用
```vue
action
{{$store.state.counter}}
```
14、Module
文档:https://next.vuex.vuejs.org/zh/guide/modules.html#%E5%B8%A6%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E7%9A%84%E7%BB%91%E5%AE%9A%E5%87%BD%E6%95%B0
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成 模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
1)在src——> store ——> 创建module文件夹(用来存储模块)
注:① 每个模块他都是一个对象; ② 每个模块里都要state、getters、action、mutation属性;
2)在module下创建你需要的文件(例:one.js)
```javascript const one = { state() { return { oneName: "模块一" } }, getters: {
},
mutations: {
},
actions: {
}
} export default one ```
3)在src——>index.js中引入
```javascript const one = { /* * 命名空间(这样设置就代表了 模块化的使用) */ namespaced: true, state() { return { oneName: "模块一" } }, getters: { /* * * @param {} state 当前的state * @param {} getters 当前的getters * @param {} rootState 根目录下的state * @param {} rootGetters 根目录下的getters */ fun1(state, getters, rootState, rootGetters) {
}
},
mutations: {
increment(state) {
state.oneName = "哈哈哈"
}
},
actions: {
/**
* 做了结构
*/
fun2({ commit, dispatch, state, rootCommit, rootDispatch, rootState }) {
commit('someMutation', null, { root: true }) // 这个代表修改根目录下的 commit的某一个事件(someMutation),这个事件写在 mutations 里
dispatch('someOtherAction', null, { root: true }) // -> 个代表修改根目录下的 dispatch的某一个事件(someOtherAction),这个事件写在 actions 里
}
}
} export default one ```
4)使用
```vue
模块1
<p>{{name}}</p>
<button @click="fun">点</button>
```
15、module的辅助函数
1)vuex的数据源
① 模块中的数据(src——>store——>module——>one.js)
```javascript const one = { namespaced: true, state() { return { oneCounter: 100 } }, getters: { doubleOneCounter(state, getters, rootState, rootGetters) { return state.oneCounter * 2 } }, mutations: { increment(state) { state.oneCounter++ } }, actions: { // 修改跟目录下的数据 incrementAction({ commit, dispatch, state, rootState, getters, rootGetters }) { commit("increment") commit("increment", null, { root: true }) } } } export default one
```
② 根目录下的数据(src——>store——>index.js)
```javascript import { createStore } from "vuex" import one from "./modules/one.js" export default createStore({ state: { name: "根模块", rootCounter: 0 }, /** * 这个里面也可以有: mutations、actions、getters */ mutations: { increment(state) { state.rootCounter++ console.log(state.rootCounter);
}
},
modules: {
one
}
}) ```
2)在setup中的使用
```javascript
{{ oneCounter }}
{{ doubleOneCounter }}
```
3)在选项API中的使用
① 方法一
```vue
{{ counter }}
{{ doubleCounter }}
```
② 方法二
```vue
{{ oneCounter }}
{{ doubleOneCounter }}
```
③ 方法三
```vue
{{ oneCounter }}
{{ doubleOneCounter }}
```
四、vuex中数据请求
1、在vuex中(store——>index.js)
javascript import { createStore } from 'vuex' import axios from 'axios' export default createStore({ state: { obj: {} }, mutations: { DATA(state, payload) { state.obj = payload } }, actions: { request(context, payload) { return new Promise((resolve, reject) => { axios({ url: "https://mock.mengxuegu.com/mock/60434bccf340b05bceda3906/practise-nuxtjs/test", method: "GET" }).then(res => { // console.log(res.data) resolve(res.data) }).catch(err => { reject(err) console.error(err) }) }) } } })
2、使用
```vue
数据请求
{{data.title}}
{{data.content}}
```