一、Vuex名词解释:
? 官方解释:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
? 白话文:前端多个组件共用一个全局属性 或 模块属性,通过对应状态改变,共享变化,可以作为 前端存储’数据库’用。
二、流程图
三、安装方式:
1.script标签 直接cdn或下载引入
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
2.npm 或者 yarn
npm install vuex@next --save
yarn add vuex@next --save
3.vue-cli 命令行创建项目时,选择vuex
J:\test\vue3>vue create my_proj
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
(*) Choose Vue version
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
>(*) Vuex
( ) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
四、开发插件Devtools
为了更方便快捷的开发vue3项目,强烈推荐大家安装chrome vue.js devtools beta版(支持vue3),目前支持查看组件、状态、路由等。
注:下载需在谷歌商店 下载插件,启用后,f12 调起开发者模式,找到vue
五、核心概念及案例实现:
1.State状态属性
实现举例代码:
import { createStore } from 'vuex'
export default createStore({
state: {
count: 0,
},
})
模板调用:
{{$store.state.count}}
js实例中调用
console.log(this.$store.state.count)
2.Getter计算属性
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
Getter 接受 state 作为其第一个参数:
Getter 也可以接受其他 getter 作为第二个参数:(一般用到getters 里面定义的其它计算属性或方法时用到)
案例1.定义属性 返回 数值结果(举例:定义一个getter 计算数值2次方的方法pow)
1./src/store/index.js 定义store计算属性pow
state: {
num: 0,
},
getters: {
pow: (state) => Math.pow(state.num, 2),
},
2.模板调用store计算属性
<h2>NUM: {{$store.state.num}}</h2>
案例2:定义属性 返回 回调函数,并利用其他计算属性的返回结果(用到 getters第二个参数)
1./src/store/index.js 定义store计算属性filterGoodsFunc 和 totalPriceFunc(用到了 getters 第二个参数)
state: {
goods: [
{
id: 1,
name: 'python王者归来',
price: 300,
},
{
id: 2,
name: 'js星耀归来',
price: 160,
},
{
id: 3,
name: 'node钻石归来',
price: 90,
},
],
},
getters: {
filterGoodsFunc: (state) => {
return (price) => {
return state.goods.filter(g => g.price > price)
};
},
totalPriceFunc: (state, getters) => {
return (price) => {
return getters.filterGoodsFunc(price).reduce((s, n) => s += n.price, 0);
}
},
},
3.Mutation 更改属性
更改state状态属性唯一正确方法,需要强调一下,直接更改state也是能实现,但是开发者工具devtools不能同步实时变化,详见上面流程图。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)**和一个**回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
举例实现:
1./src/store/index.js 中 mutations 定义 inc 自增方法,第一个默认state状态对象,第二个参数可以装载一个或多个参数(json对象实现)
import { createStore } from 'vuex'
export default createStore({
state: {
num: 0,
},
mutations: {
inc(state, payload){
console.log(payload)
if(state.num < payload.maxNum){
state.num += payload.step;
}
},
},
actions: {
},
modules: {
}
})
2.模板事件 调用mutations方法 改变状态
<button @click="$store.commit('inc',{step: 2, maxNum: 100})">多参数状态传递</button>
3.模板渲染 展示状态值
<h2>获取状态num值:{{$store.state.num}}</h2>
4.Action 事件属性
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
举例实现:
1./src/store/index.js 中 使用 actions token方法 实现网络获取token,并通过mutations 设置token(setToken方法)来改变state 值
state: {
token: '',
},
mutations: {
setToken(state, payload) {
state.token = payload.token;
},
},
actions: {
token({commit}, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let token = 'aaaaaaaaaaaaaabb';
commit('setToken', {token});
console.log(payload);
let rst = {errcode: 0, msg: 'success', data: {token}};
if (rst.errcode === 0) {
resolve(rst);
} else {
reject({errcode: -1, msg: 'error', data: {}});
}
}, 3000);
});
}
},
2.模板中js 调用 actions 并传参,多个参数可通过json对象传递,如果actions 返回promise(例如axios请求),可以通过then和catch 链式调用:
methods: {
getToken(){
this.$store.dispatch('getToken',{a: 1, b: 2}).then((rst)=>{
console.log(rst);
}).catch((err)=>{
console.log(err);
});
}
},
dispatch 方法 可以直接派遣 actions 指定方法 执行调用,并且可以通过第二个参数json对象传递多参数
5.Module 模块属性
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
例如 将用户user 状态管理 分成user模块
/src/store/modules/user.js
代码举例解析:
局部状态调用(模块状态)
store.state.user.xxx
模块的局部状态
1.局部state 要用回调函数返回json对象
state: () => {
return {
nickname: '编程热',
intro: '编程源于热爱',
token: '',
};
},
2.对于模块内部的
mutation: 第一个参数为局部状态state对象,第二个参数为传参的对象,多个参数json对象实现。
getter:第一个参数是模块的局部状态state对象,第二个参数为局部计算属性getters,第三个参数为根状态rootState,第四个参数为根计算属性rootGetters
mutations: {
setNickname(state, payload){
state.nickname = payload.nickname;
}
},
getters: {
getText: (state) => {
return state.nickname + '-' + state.intro;
},
getFullText: (state, getters, rootState, rootGetters) => {
console.log(rootState);
console.log(rootGetters);
return getters.getText + ',用心写好每一行代码!';
},
},
3.对于模块内部的 action 默认参数为context上下文,可以通过解构赋值格式 解析如下
commit, dispatch, getters, rootGetters, state, rootState
actions: {
getToken({commit, dispatch, getters, rootGetters, state, rootState}, payload) {
console.log(dispatch);
console.log(getters);
console.log(rootGetters);
console.log(state);
console.log(rootState);
return new Promise((resolve, reject) => {
setTimeout(() => {
let token = 'aaaaaaaaaaaaaabb';
commit('setToken', {token});
console.log(payload);
let rst = {errcode: 0, msg: 'success', data: {token}};
if (rst.errcode === 0) {
resolve(rst);
} else {
reject({errcode: -1, msg: 'error', data: {}});
}
}, 3000);
});
}
}
4.对于模块内部的modules 可以再嵌套子模块类似当前(不建议子模块再嵌套,可读性差)
modules: {
myPage: {
state: () => ({ ... }),
getters: {
profile () { ... }
}
},
},
5.命名空间
默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:
export default {
namespaced: true,
state: () => {
},
...
}
启用命名空间后,模板调用的时:
- state 调用方式不变
- getters.getText --> getters[‘user/getText’]
- $store.commit(‘setNickname’) --> $store.commit(‘user/setNickname’)
<p>state.user.nickname {{$store.state.user.nickname}} </p>
<p>text: {{$store.getters['user/getText']}} </p>
<p>fulltext: {{$store.getters['user/getFullText']}} </p>
<button @click="$store.commit('user/setNickname',{nickname:'bian cheng re'})">设置用户名</button>
在带命名空间的模块内访问全局内容(Global Assets)
如果你希望使用全局 state 和 getter,rootState 和 rootGetters 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。
若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。
<button
@click="$store.commit('user/setNickname',{nickname:'bian cheng re'},{ root: true})">
设置用户名
</button>
|