vue中避免多次请求字典接口

vuex缓存所有字典项

背景

每次用到字典都需要通过对应的字典type调用一次字典接口,当一个页面用到字典项很多时,接口请求炒鸡多,会导致接口响应超时。
本篇文章改为调用接口将所有字典项请求回存到vuex中,需要时通过过滤数据的方式解决这一问题。

vuex管理所有字典项

  1. 新建src\store\modules\dict.js文件
  2. 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,
};
  1. 在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,调用成功后更新字典数据(也可以放到登录成功后,这种情况如果想要刷新字典数据,只能退出重新登录)。

  1. 关键代码
bash 复制代码
// 获取用户接口下的代码
let queryParams = {
	pageNum: 1,
    pageSize: 100000, //这块完全是因为后端不想再开接口,用的之前分页的接口,所以传了巨大个值
};
listData(queryParams).then((response) => {
	let dictData = response.rows;
    store.commit("SET_ALL_DICT", dictData);
});

处理字典项数据的filter

  1. 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;
  1. 将过滤方法注册到全局
bash 复制代码
import dict from "./filters/dict";
// 注册所有过滤方法
for (let key in dict) {
  Vue.filter(key, dict[key]);
}

页面中使用字典

  1. 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>
  1. 表单组件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", 
        },
      ]
	}
}
相关推荐
落魄切图仔18 分钟前
echarts柱状选中shadow阴影背景宽度设置
前端·javascript·echarts
ZJ_.27 分钟前
Node.js 使用 gRPC:从定义到实现
java·开发语言·javascript·分布式·rpc·架构·node.js
阿垚啊1 小时前
列表渲染 v-for
前端·javascript·vue.js·html
铁匠匠匠1 小时前
django学习入门系列之第三点《BootSrap初了解》
前端·经验分享·笔记·python·学习·django·前端框架
曲辒净1 小时前
如何实现图片垂直旋转90度的问题
javascript
前端宝哥1 小时前
Composition API VS Options API:谁才是你的最佳选择?
前端·javascript·vue.js
不露声色丶1 小时前
elementPlus表格二次封装
前端·javascript·vue.js
王天乐0071 小时前
ElementUI的搭建
前端·javascript·elementui
小秋菇娘2 小时前
vue 启动项目报错Syntax Error: Error: PostCSS received undefined instead of CSS string
css·vue.js·postcss
OpenTiny社区2 小时前
7月6日 VueConf 技术大会即将在深圳举办
前端·vue.js·github