【UniApp 实战】封装通用字典 Mixin,高效管理全局数据字典。附真实案例若依管理后台字典通用!!
在Vue企业级项目开发中,字典数据管理是一个常见且重要的需求。不同的模块和组件通常需要共享相同的字典数据,如何高效地管理这些数据,避免重复请求,同时保证数据的实时性和一致性,是前端架构中需要解决的关键问题。本文将介绍如何通过Vue Mixin实现一个优雅的全局字典数据管理方案。
一、字典数据管理的挑战
在管理系统中,我们经常需要处理各种字典数据(如状态类型、分类选项等),这些数据通常具有以下特点:
- 多个组件需要使用相同的字典数据
- 字典数据相对稳定,不经常变化
- 需要支持按需加载和缓存机制
- 需要提供便捷的数据访问方法
传统的实现方式往往导致代码重复、请求冗余或状态管理复杂等问题。而Vue Mixin提供了一种优雅的解决方案。
二、Vue Mixin方案设计
下面是一个完整的字典数据管理Mixin实现:
用过若依后台管理系统的都知道getDicts这个接口,childrenDicts这个是因为我们实际项目需求中有很多字段是需要自己去配置的,否则的话只需要用到getDicts此方法就好对应后续的dictOptions()方法。
// 字典缓存存储(全局共享)
const globalDictStore = {}
import {
getDicts,
childrenDicts,
} from '@/api/index.js'
export default {
data() {
return {
// 组件级字典状态
dictLoading: {},
dictErrors: {}
}
},
methods: {
/**
* 加载字典数据
* @param {string} dictType 字典类型
* @param {string} textField 文本字段名 (默认'dictLabel')
* @param {string} valueField 值字段名 (默认'dictValue')
* @param {boolean} forceRefresh 是否强制刷新
* @param {boolean} isNew 是否使用childrenDicts方法
* @returns {Promise<Array>} 字典数据
*/
async loadDict(
dictType,
textField = 'dictLabel',
valueField = 'dictValue',
forceRefresh = false,
isNew = false
) {
// 防抖处理 - 避免重复请求
if (this.dictLoading[dictType]) {
return new Promise(resolve => {
const checkInterval = setInterval(() => {
if (!this.dictLoading[dictType]) {
clearInterval(checkInterval)
resolve(globalDictStore[dictType] || [])
}
}, 50)
})
}
try {
// 标记为加载中
this.$set(this.dictLoading, dictType, true)
this.$delete(this.dictErrors, dictType)
// 检查缓存是否存在且不需要强制刷新
if (globalDictStore[dictType] && !forceRefresh) {
return globalDictStore[dictType]
}
// 根据isNew选择请求方法
const res = isNew ? await childrenDicts(dictType) : await getDicts(dictType)
if (res.code === 200 && Array.isArray(res.data)) {
// 处理字典数据
const mappedData = res.data.map(item => ({
text: item[textField],
value: item[valueField],
rawData: item // 保留原始数据
}))
// 更新全局缓存
globalDictStore[dictType] = mappedData
return mappedData
}
throw new Error(res.msg || '字典数据格式错误')
} catch (error) {
console.error(`加载字典 ${dictType} 失败:`, error)
this.$set(this.dictErrors, dictType, error.message)
return []
} finally {
// 清除加载状态
this.$set(this.dictLoading, dictType, false)
}
},
/**
* 获取字典文本(模板中使用)
* @param {string} dictType 字典类型
* @param {string|number} value 值
* @param {string} defaultValue 默认值
* @param {boolean} isNew 是否使用childrenDicts方法
* @returns {string} 字典文本
*/
dictText(dictType, value, defaultValue = '', isNew = false) {
const dict = globalDictStore[dictType]
if (!dict) {
// 按需加载字典(静默)
this.loadDict(dictType, 'dictLabel', 'dictValue', false, isNew).catch(() => {})
return defaultValue
}
const item = dict.find(d => d.value == value)
return item ? item.text : defaultValue
},
/**
* 获取字典选项(模板中使用)
* @param {string} dictType 字典类型
* @param {boolean} includeAll 是否包含"全部"选项
* @param {boolean} isNew 是否使用childrenDicts方法
* @returns {Array} 字典选项数组
*/
dictOptions(dictType, includeAll = false, isNew = false) {
const dict = globalDictStore[dictType] || []
if (!globalDictStore[dictType]) {
// 按需加载字典(静默)
this.loadDict(dictType, 'dictLabel', 'dictValue', false, isNew).catch(() => {})
}
if (includeAll) {
return [{
text: '全部',
value: ''
}, ...dict]
}
return dict
},
/**
* 获取原始字典数据
* @param {string} dictType 字典类型
* @param {boolean} isNew 是否使用childrenDicts方法
* @returns {Array} 原始字典数据
*/
getRawDict(dictType, isNew = false) {
const dict = globalDictStore[dictType]
if (!dict) {
// 按需加载字典(静默)
this.loadDict(dictType, 'dictLabel', 'dictValue', false, isNew).catch(() => {})
return []
}
return dict.map(item => item.rawData)
}
}
}
三、核心特性解析
1. 全局缓存机制
通过globalDictStore对象实现全局字典缓存,所有组件共享同一份字典数据,避免重复请求:
// 字典缓存存储(全局共享)
const globalDictStore = {}
2. 请求防抖与状态管理
使用dictLoading和dictErrors状态跟踪每个字典的加载状态和错误信息:
data() {
return {
// 组件级字典状态
dictLoading: {},
dictErrors: {}
}
}
3. 智能按需加载
当组件需要字典数据时,首先检查缓存,不存在时再发起请求:
// 检查缓存是否存在且不需要强制刷新
if (globalDictStore[dictType] && !forceRefresh) {
return globalDictStore[dictType]
}
4. 多种数据访问方式
提供三种便捷的数据访问方法,满足不同场景需求:
- dictText(): 获取字典项文本
- dictOptions(): 获取选项列表(支持包含"全部"选项)
- getRawDict(): 获取原始字典数据
四、使用示例
1.在main.js全局注入使用
// 全局混入字典管理
import dictMixin from '@/utils/dictmixin.js'
Vue.mixin(dictMixin)
2.在Vue组件中使用Mixin
<view class="form_input_flex">
<view class="form_text"><span>*</span>客户类型 </view>
<view class="form_select">
<formSelect v-model="addFormData.type" :localdata="dictOptions('self_customer_type')"></formSelect>
</view>
</view>
<view class="form_input_flex">
<view class="form_text"><span>*</span>线索来源</view>
<view class="form_select">
<formSelect v-model="addFormData.source" :localdata="dictOptions('客户来源',false,true)"></formSelect>
</view>
</view>
async onLoad(option) {
await this.loadDict('客户来源', 'name', 'name', false, true)
},
formSelect 这个组件是我自己封装的,跟uniapp中的下拉组件基本一样多了回显样式。
五、优势与特点
- 全局共享:所有组件共享同一份字典数据,减少重复请求
- 按需加载:只有在需要时才加载字典数据,提升性能
- 自动缓存:已加载的字典数据会被缓存,提高后续访问速度
- 错误处理:完善的错误处理机制,避免因字典加载失败导致页面异常
- 灵活配置:支持自定义字段映射和强制刷新
- 类型友好:完整的JSDoc注释,提供良好的类型提示
六、总结
通过Vue Mixin实现字典数据管理是一种高效且优雅的解决方案。它既保持了代码的简洁性,又提供了强大的功能特性。这种模式不仅可以应用于字典数据管理,还可以推广到其他需要全局状态共享和复用的场景中。
在实际项目中,我们可以根据具体需求进一步扩展这个Mixin,例如添加字典数据变更通知、本地存储持久化、请求重试机制等功能,使其更加完善和健壮。
更多推荐



所有评论(0)