vuex缓存所有字典项
背景
每次用到字典都需要通过对应的字典type调用一次字典接口,当一个页面用到字典项很多时,接口请求炒鸡多,会导致接口响应超时。
本篇文章改为调用接口将所有字典项请求回存到vuex中,需要时通过过滤
数据的方式解决这一问题。
vuex管理所有字典项
- 新建src\store\modules\
dict.js
文件 - dict.js完整代码
bash
const state = {
// 存储所有字典项
allDict: new Array(),
};
const mutations = {
SET_ALL_DICT: (state, data) => {
state.allDict = data;
},
CLEAN_ALL_DICT: (state) => {
state.allDict = new Array();
},
};
const actions = {
setAllDict({ commit }, data) {
commit("SET_ALL_DICT", data);
},
cleanAllDict({ commit }) {
commit("CLEAN_ALL_DICT");
},
};
export default {
state,
mutations,
actions,
};
- 在src\store\index.js中引入dict.js
bash
import Vue from "vue";
import Vuex from "vuex";
import app from "./modules/app";
import user from "./modules/user";
import tagsView from "./modules/tagsView";
import permission from "./modules/permission";
import settings from "./modules/settings";
import getters from "./getters";
import businessDictAll from "./modules/businessDictAll"; //引入
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
app,
user,
tagsView,
permission,
settings,
businessDictAll,
},
getters,
});
export default store;
4.src\store\getter.js中添加allDict
bash
const getters = {
sidebar: state => state.app.sidebar,
size: state => state.app.size,
device: state => state.app.device,
dict: state => state.dict.dict,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
permissions: state => state.user.permissions,
permission_routes: state => state.permission.routes,
topbarRouters:state => state.permission.topbarRouters,
defaultRoutes:state => state.permission.defaultRoutes,
sidebarRouters:state => state.permission.sidebarRouters,
allDict: state => state.businessDictAll.allDict, //所有字典项
}
export default getters
调用字典接口
我这块在src\store\modules\user.js中的的
getInfo
后调用的字典接口并存储字典数据,我放这的目的是当页面刷新会调用getInfo,调用成功后更新字典数据(也可以放到登录成功后,这种情况如果想要刷新字典数据,只能退出重新登录)。
- 关键代码
bash
// 获取用户接口下的代码
let queryParams = {
pageNum: 1,
pageSize: 100000, //这块完全是因为后端不想再开接口,用的之前分页的接口,所以传了巨大个值
};
listData(queryParams).then((response) => {
let dictData = response.rows;
store.commit("SET_ALL_DICT", dictData);
});
处理字典项数据的filter
- src\filters\dict.js完整代码
bash
import store from "@/store";
const allDict = {
// 处理select这类表单项数据
// 如果有字典名dictName则过滤字典,若没有取当前表单项的option属性(这块是通过接口返回的数据字段)
dictOption: function (formItem) {
if (formItem.dictName) {
let type = formItem.dictName;
let dictList = [];
if (type && typeof type === "string") {
const dicts = store.getters && store.getters.allDict;
dictList = dicts.filter((item) => item.dictType === type);
} else {
console.error(`字典获取失败`);
}
return dictList;
} else {
return formItem.option;
}
},
// table中根据dictValue字段匹配对应dictLabel值
dictAll: function (value, type) {
let dictList = [];
let foundItem = {};
if (type && typeof type === "string") {
const dicts = store.getters && store.getters.allDict;
dictList = dicts.filter((item) => item.dictType === type);
foundItem = dictList.find((item) => item.dictValue === value);
} else {
console.error(`字典获取失败`);
}
//如果过滤到了就返回dictLabel,
// 否则判断当前是否有返回数据,如果有返回的数据,直接将数据返回
// 否则接口没返回数据给table显示'-'(可根据需要去处理,我这块是因为table中数据为空要显示-)
return foundItem ? foundItem.dictLabel : value ? value : "-";
},
};
export default allDict;
- 将过滤方法注册到全局
bash
import dict from "./filters/dict";
// 注册所有过滤方法
for (let key in dict) {
Vue.filter(key, dict[key]);
}
页面中使用字典
- table中使用
bash
<baseTable
:columns="columns"
:loading="loading"
:tableData="tableData"
:total="total"
:queryParams="queryParams"
:tableH="tableH"
@getList="getList"
>
<template #modeCode="record">
<!-- 调用filter方法,record.row.modeCode为当前接口返回值,dictAll为全局过滤方法,mode_code为字典项名 -->
<span>{{ record.row.modeCode | dictAll("mode_code") }}</span>
</template>
<template #action="record">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="tableAction('update', record.row)"
>编辑</el-button
>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="tipClick"
>删除</el-button
>
</template>
- 表单组件select和radio使用
bash
<template>
<div>
<el-form
:model="formModel"
:rules="rules"
ref="baseForm"
:label-width="'120px'"
>
<el-row :gutter="gutter">
<div v-for="(item, index) in formData" :key="index">
<el-col :span="item.span || 8" v-if="!item.hidden">
<el-form-item :label="item.label" :prop="item.name">
<!-- 省略组件其他表单项(具体可查看组件那篇) -->
<!-- 单选框 -->
<el-radio-group
v-if="item.type === 'radio'"
v-model="formModel[item.name]"
:disabled="item.disabled || !isUpdate"
@input="radioChange"
>
<el-radio
v-for="list in optionDicts(item)"
:key="list.value || list.dictValue"
:label="list.value || list.dictValue"
>
{{ list.label }}
</el-radio>
</el-radio-group>
<!-- select选择器 -->
<el-select
size="small"
v-if="item.type === 'select'"
filterable
:disabled="item.disabled || !isUpdate"
v-model="formModel[item.name]"
:placeholder="item.disabled ? '' : '请选择' + item.label"
:multiple="item.multiple"
style="width: 100%"
@change="change(item.name, formModel[item.name])"
>
<el-option
v-for="list in optionDicts(item)"
:key="list.value || list.dictValue"
:label="list.label || list.dictLabel"
:value="list.value || list.dictValue"
/>
</el-select>
<!-- 自定义 -->
<template v-if="item.type == 'slot'" #default>
<slot :name="item.name"></slot>
</template>
</el-form-item>
</el-col>
</div>
</el-row>
</el-form>
</div>
</template>
methods: {
optionDicts(item) {
//通过this.$options.filters调用处理表单项的过滤方法
return this.$options.filters["dictOption"](item);
}
}
// 下面是给表单组件的栗子数据
data() {
return {
formItems: [
{
label: "XXX模式",
type: "select",
key: "modeCode",
placeholder: "请选择XXX模式",
dictName: "mode_code",
},
]
}
}