一、Vue3 中的字典应用场景
在 Vue3 中,“字典”通常指用于数据映射、状态翻译、下拉选项等场景的键值对集合,常见于:
- 下拉选择框(Select):如性别、状态、类型等选项的映射;
- 表单校验提示:根据错误类型显示对应提示信息;
- 国际化(i18n):多语言文本的键值映射;
- 状态枚举:如订单状态(
{ 1: '待支付', 2: '已发货' }
)。
二、字典的定义与管理方式
1. 组件内字典(局部字典)
- 定义在
setup
或data
中:<script setup> // 简单字典(对象形式) const genderDict = { 1: '男', 2: '女', 3: '保密' }; // 带描述的复杂字典(数组形式) const statusDict = [ { value: 1, label: '待处理', color: 'yellow' }, { value: 2, label: '处理中', color: 'blue' }, { value: 3, label: '已完成', color: 'green' } ]; </script>
- 模板中使用:
<template> <select v-model="selectedGender"> <option v-for="(label, value) in genderDict" :key="value">{{ label }}</option> </select> <div v-for="item in statusDict" :key="item.value"> <span :style="{ color: item.color }">{{ item.label }}</span> </div> </template>
2. 全局字典(跨组件共享)
- 通过
app.config.globalProperties
挂载:// main.js const app = createApp(App); // 全局字典 app.config.globalProperties.$dict = { yesNo: { 0: '否', 1: '是' }, priority: { 1: '低', 2: '中', 3: '高', 4: '紧急' } }; app.mount('#app');
- 组件中使用:
<script setup> import { getCurrentInstance } from 'vue'; const { appContext } = getCurrentInstance(); const globalDict = appContext.config.globalProperties.$dict; console.log(globalDict.yesNo[1]); // '是' </script>
3. 使用 Pinia 管理字典(推荐大型项目)
- 创建字典存储模块:
// store/dict.js import { defineStore } from 'pinia'; export const useDictStore = defineStore('dict', { state: () => ({ gender: { 1: '男', 2: '女' }, status: [ { value: 1, label: '新建', color: 'gray' }, { value: 2, label: '进行中', color: 'blue' } ] }), getters: { // 封装获取带颜色的状态标签 getStatusLabel: (state) => (value) => { const item = state.status.find(item => item.value === value); return item ? item.label : '未知'; } }, actions: { // 异步加载字典数据(如从后端获取) async fetchDictData() { const res = await fetch('/api/dict'); Object.assign(this, res.data); } } });
- 组件中使用:
<script setup> import { useDictStore } from '@/store/dict'; const dictStore = useDictStore(); // 加载字典数据 dictStore.fetchDictData(); // 使用字典 const statusLabel = dictStore.getStatusLabel(2); // '进行中' </script>
三、字典的动态加载与优化
1. 后端接口获取字典数据
- 场景:字典数据需动态更新或由后端维护(如权限角色、部门列表)。
- 实现:
<script setup> import { ref, onMounted } from 'vue'; const roleDict = ref({}); onMounted(async () => { const res = await fetch('/api/roles'); roleDict.value = res.data.reduce((obj, item) => { obj[item.id] = item.name; return obj; }, {}); }); </script>
2. 字典数据的缓存策略
- 避免重复请求:
// 字典服务 const dictCache = new Map(); async function getDict(key) { if (dictCache.has(key)) { return dictCache.get(key); } const res = await fetch(`/api/dict/${key}`); dictCache.set(key, res.data); return res.data; }
四、字典在模板中的高级用法
1. 结合计算属性动态转换
- 示例:订单状态文本与样式转换
<script setup> const order = ref({ status: 2 }); // 2表示"进行中" const statusDict = { 1: '待支付', 2: '进行中', 3: '已完成', 4: '已取消' }; const statusStyle = computed(() => { const status = order.value.status; const styleMap = { 1: 'text-yellow-500', 2: 'text-blue-500', 3: 'text-green-500', 4: 'text-red-500' }; return styleMap[status] || ''; }); </script> <template> <div :class="statusStyle"> {{ statusDict[order.status] || '未知状态' }} </div> </template>
2. 自定义指令实现字典转换
- 场景:批量转换表格中的字典值
<script setup> import { defineDirective } from 'vue'; // 字典转换指令 v-dict const dictDirective = defineDirective({ mounted(el, binding) { const { dict, key } = binding.value; if (dict && key in dict) { el.textContent = dict[key]; } } }); const genderDict = { 1: '男', 2: '女' }; </script> <template> <div v-dict="{ dict: genderDict, key: user.gender }"></div> </template>
五、问题
1. 问:为什么不直接在模板中写死字典值,而要单独管理?
- 答:
- 可维护性:字典集中管理便于修改(如新增状态值时无需修改所有使用处);
- 复用性:跨组件共享字典,避免重复定义;
- 动态性:支持从后端获取字典数据,适应业务变化(如角色权限新增时无需前端发布)。
2. 问:大型项目中如何优化字典的加载性能?
- 答:
- 按需加载:仅加载当前页面需要的字典(如订单页加载订单状态字典,用户页加载用户类型字典);
- 缓存策略:使用
Map
或本地存储缓存字典数据,避免重复请求; - 合并请求:将多个字典请求合并为一个API调用(如
/api/dict?keys=status,gender
)。
3. 问:Vue3 中如何实现字典的响应式更新?
- 答:
- 若字典定义在
setup
中,使用ref
或reactive
包装即可响应式; - 若通过
app.config.globalProperties
挂载全局字典,需注意:- 普通对象需用
reactive
包装(如app.config.globalProperties.$dict = reactive({})
); - 数组类型字典需使用
push
、splice
等变异方法修改,或重新赋值整个数组。
- 普通对象需用
- 若字典定义在