持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
背景
开发过程中,系统一般都会维护字典数据。将一个系统中的属性值定义成字典。比如,性别,城市,岗位,学历,名族等。
字典数据的种类很多,系统中每个页面用到字典数据的地方都要,去请求接口,比如A页面中用到的性别这个字典数据,A页面中的一个弹窗也用到了性别数据,打开弹窗的时候就会再次请求这个数据,当需要的字段很多时,就会发起大量的请求字典数据请求。
现在的需求是,只需一次请求,然后将请求的该类型的字典数据缓存起来,下次用的时候先从缓存数据中找,如果有的话就直接用,没有的话再去请求。
刚好使用 vuex 可以轻松的实现上述的需求。
先来复习以下vuex的用法吧
vuex 的 4 个属性 :State, Mutations,Actions,Getters
-
state:我们要把我们需要做状态管理的量放到这里来,然后在后面的操作动它
-
mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
-
actions:
action 类似于 mutation,不同在于:
action 提交的是 mutation,而不是直接变更状态。
action 中可以写异步
-
getters: 用于存取数据
步骤
1.在项目中创建文件夹 store
store 的结构如下:
- modules 文件夹中存放不同功能的vuex代码
- getters.js 汇总
modules文件夹中的getter - index.js 入口文件
2.创建并编写 index.js
在main.js中导入import store from './store/index'
index.js:整合modules
import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";
Vue.use(Vuex);
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context("./modules", true, /\.js$/);
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
const value = modulesFiles(modulePath);
modules[moduleName] = value.default;
return modules;
}, {});
const store = new Vuex.Store({
modules,
getters,
});
export default store;
require.context() 方法创建自己的(模块)上下文,方法有 3 个参数:
- 要搜索的文件夹目录
- 是否还应该搜索它的子目录,
- 以及一个匹配文件的正则表达式。
3.创建并编写 getter.js
getter.js
export default {
dict: (state) => state.dict.dict,
};
4.创建并编写 dict.js
dict 的数据结构:通过键值对取存储字典。
interface ditc{
codeName:String
codeValue:Array
}
每次我们需要字典数据时都从 dict 中去匹配,比如关于性别的字典数据:
sex:[
{
label:'男',
value:'01'
},
{
label:'女',
value:'02'
},
]
dict.sex 如果有值就把值取出来,通过 Promise 方法 resolve 出去。如果没有,就去调接口请求数据,拿到数据后,需要做下面两步操作。
1.queryByClaCode()是用来请求后台数据的接口,把拿到的数据存到 vuex 中。
commit("SET_DICT", {
key: code,
value: option,
});
2.配置键名,如果缓存中存在返回数据,如果不存在请求后返回,并将数据缓存起来
resolve({ option })
dict.js 的完整代码:
import { queryByClaCode } from "@/apis/system";
const state = {
dict: {},
};
const mutations = {
SET_DICT(state, object) {
let { key, value } = object;
try {
state.dict[key] = value;
} catch (error) {
console.log(error);
}
},
};
const actions = {
// query
getDictionary({ commit, state }, code) {
return new Promise((resolve, reject) => {
let dict = state.dict;
if (!dict[code] || (dict[code] && dict[code].length === 0)) {
//当缓存中没有时去请求
queryByClaCode(code)
.then((res) => {
let option = res.data || [];
commit("SET_DICT", {
key: code,
value: option,
});
resolve({ option });
})
.catch(() => {
reject(false);
});
} else {
resolve({ option: dict[code] });
}
});
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};
5.使用
1.通过 dispatch
// codeName 字典名
this.$store.dispatch("dict/getDictionary", codeName).then((res) => {
let codeOption = res.option || [];
});
2.通过 mapGetters函数
import {mapGetters} from 'vuex'
computed:{
...mapGetters([dict['sex']])
}
3.更新字典
this.$store.commit('dict/SET_DICT', {'sex':['m':'男','w':'女']});
总结
算是一个开发中优化的一个小技巧吧,开发的上一个项目中需要大量请求这些字段数据,甚至有的数据可以达到上千条,到此也没什么,就这点数据量也不会造成严重性能影响,只是后来需求变更,需要在表格中编辑这些数据,甚至是批量编辑,表格中一条数据20多个字段有下拉数据,每次编辑状态的切换都会去请求字典数据。导致页面有明显的卡顿,继更换 v-if 为 v-show 等操作后,做个这次优化操作。