在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. 请求防抖与状态管理

使用dictLoadingdictErrors状态跟踪每个字典的加载状态和错误信息:

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中的下拉组件基本一样多了回显样式。

五、优势与特点

  1. 全局共享:所有组件共享同一份字典数据,减少重复请求
  2. 按需加载:只有在需要时才加载字典数据,提升性能
  3. 自动缓存:已加载的字典数据会被缓存,提高后续访问速度
  4. 错误处理:完善的错误处理机制,避免因字典加载失败导致页面异常
  5. 灵活配置:支持自定义字段映射和强制刷新
  6. 类型友好:完整的JSDoc注释,提供良好的类型提示

六、总结

通过Vue Mixin实现字典数据管理是一种高效且优雅的解决方案。它既保持了代码的简洁性,又提供了强大的功能特性。这种模式不仅可以应用于字典数据管理,还可以推广到其他需要全局状态共享和复用的场景中。

在实际项目中,我们可以根据具体需求进一步扩展这个Mixin,例如添加字典数据变更通知、本地存储持久化、请求重试机制等功能,使其更加完善和健壮。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐