项目场景:
在项目中,一个表格里可能会有一个数据属于字典类型,然后使用字典转义公共组件,如下:(dict-show文件在下方相关代码下)
这样就会有一个问题,每条数据都需要调用一次字典接口,同一个接口多次调用,控制台如下:
注意:不同的dictType的多次调用是正常的,因为参数不一样,只能每次都调用;这里的多次调用只的是同样参数同样接口的多次调用
相关代码
dict-show.vue 字典文件:
<template>
<div>
<el-input v-if="isInput" :value="dictName" readonly :disabled="disabled"/>
<span v-else>{{ dictName }}</span>
</div>
</template>
<script>
import { getDictDataByDictType} from "@/api/common.js";
export default {
name: "DictShow",
components: {},
props: {
dictId: {
type: String,
default: ""
},
dictType: {
type: String,
required: false,
default: ""
},
isInput: {
type: Boolean,
default: false,
},
disabled:{
type: Boolean,
default: false,
}
},
data() {
return {
dictName: "",
dictArr:[],
dictNameArr: []
};
},
watch: {
dictId(val) {
if (val) {
this.getDictArr();
} else {
this.dictName = ""
}
},
},
mounted() {
if (this.dictId) {
this.getDictArr();
} else {
this.dictName = ""
}
},
methods: {
//根据dictId在字典列表中找到对应文字(可多个)
getDictName() {
this.dictNameArr = []
const arr = this.dictId.split(",");
for (let i = 0; i < arr.length; i++) {
let tem = this.dictArr.filter(item=>{
return item.dictValue === arr[i]
})
tem = tem && tem.length > 0 ? tem[0].dictLabel : "";
this.dictNameArr.push(tem)
}
if (this.dictNameArr.length === 1) {
this.dictName = this.dictNameArr[0]
} else {
let str = ''
for (let i = 0; i < this.dictNameArr.length; i++) {
str += this.dictNameArr[i] + ','
}
this.dictName = str.slice(0,-1)
}
},
//获取字典列表
getDictArr () {
getDictDataByDictType(this.dictType).then(res => {
this.dictArr = res.data
if (this.dictArr.length > 0) {
this.getDictName();
}
})
.catch((err) => {});
}
},
};
</script>
api/common.js文件:
import axios from 'axios'
export const getDictDataByDictType = (dictType) => {
return axios.request({
url: "/getDictDataListByDictType",
params: {
dictType: dictType
}
})
}
解决方案:添加remote.js文件,并在接口封装时使用:
解决后的api/common.js文件,多封装一层:
import { remoteRequest } from '@/utils/remote.js'
import axios from 'axios'
export const getDictDataByDictType = (dictType) => {
return remoteRequest('getDictDataByDictType', dictType, () => {
return axios.request({
url: "/getDictDataListByDictType",
params: {
dictType: dictType
}
})
})
}
utils/remote.js文件(可直接拿去用):
const cache = new Map()
const cacheTime = new Map()
/**
* 远程获取[避免重复请求]
* @param prefix 前缀
* @param params 参数配置
* @param remoteFunc 反馈参数
* @param repeatRequest 是否重复请求
* @returns {Promise<any>|Promise<T | never>}
*/
export function remoteRequest(prefix, params, remoteFunc, repeatRequest = true, requestTime = 10000) {
if (params == null) {
return new Promise((resolve) => {
resolve([])
})
}
const timeKey = prefix + '#' + JSON.stringify(params)
let time = ''
if (repeatRequest) {
const curTime = new Date().getTime()
time = cacheTime.get(timeKey)
if (time == null) {
cacheTime.set(timeKey, curTime)
time = curTime
}
if (curTime - requestTime >= time) { // 2秒内的请求都重新请求
// 清除缓存换个请求
cacheTime.clear()
cacheTime.set(timeKey, curTime)
time = curTime
}
}
const key = timeKey + '#' + time
// 远程获取
let item = cache.get(key)
if (item == null || item.error === true) {
// 还没加载过
if (item == null) {
item = { loading: true, callbacks: [] }
cache.set(key, item)
}
item.loading = true
item.error = false
// 远程加载
return remoteFunc().then((data) => {
// prop mapping
item.data = data
// 之前注册过的callback全部触发
for (const callback of item.callbacks) {
callback(item.data)
}
item.loading = false
item.callbacks = []
return data
}).catch(() => {
item.loading = false
item.error = true
})
} else if (item.loading === true) {
// 正在加载中,注册callback,等加载完了之后,再统一触发,就只需要向服务器请求一次数据模版
return new Promise((resolve) => {
const callback = (data) => {
resolve(data)
}
item.callbacks.push(callback)
})
} else {
// 从缓存拿
return new Promise((resolve) => {
resolve(item.data)
})
}
}
const cacheTrans = new Map()
const cacheTransTime = new Map()
/**
* 远程获取数据合并同一请求 [避免重复请求]
* @param prefix 前缀
* @param id 参数配置
* @returns {Promise<any>|Promise<T | never>}
*/
export function remoteTransRequest(prefix, id) {
// 当id变化了(不一致)时,仍然认为是同意请求,不合理
// prefix作为Map的key,应具有唯一性,所以加上参数,使其唯一性加强
if (Object.prototype.toString.call(id) === '[object Object]') {
prefix = prefix + '#' + JSON.stringify(id)
} else {
prefix = prefix + '#' + id
}
const curTime = new Date().getTime()
const timeOut = 2000
let time = cacheTransTime.get(prefix)
if (time == null) {
cacheTransTime.set(prefix, curTime)
time = curTime
}
if (curTime - timeOut >= time) { // 2秒内的请求都重新请求
// 清除缓存换个请求
cacheTransTime.clear()
cacheTransTime.set(prefix, curTime)
time = curTime
}
const key = prefix + '#' + time
// 汇总接口
let item = cacheTrans.get(key)
let idVal = id
if (Object.prototype.toString.call(id) === '[object Object]') {
idVal = JSON.stringify(id)
}
if (item == null || item.error === true) {
// 还没加载过
if (item == null) {
item = { loading: true, ids: new Set(), callbacks: [] }
cacheTrans.set(key, item)
}
item.loading = true
item.ids = item.ids.add(idVal)
const remoteFunc = (ids) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(ids)
}, 100)
})
}
return remoteFunc(item.ids).then((ids) => {
item.ids = ids
// 之前注册过的callback全部触发
for (const callback of item.callbacks) {
callback(ids)
}
item.loading = false
item.callbacks = []
return ids
})
} else if (item.loading === true) {
// 正在加载中,注册callback,等加载完了之后,再统一触发,就只需要向服务器请求一次数据模版
return new Promise((resolve) => {
const callback = (ids) => {
item.ids = ids.add(idVal)
resolve(item.ids)
}
item.callbacks.push(callback)
})
} else {
// 从缓存拿
return new Promise((resolve) => {
resolve(item.ids)
})
}
}
总结
之后再打开控制台,就都只有一次啦!
写博客是为了记笔记!