vue3字典

2 阅读2分钟

一、Vue3 中的字典应用场景

在 Vue3 中,“字典”通常指用于数据映射、状态翻译、下拉选项等场景的键值对集合,常见于:

  • 下拉选择框(Select):如性别、状态、类型等选项的映射;
  • 表单校验提示:根据错误类型显示对应提示信息;
  • 国际化(i18n):多语言文本的键值映射;
  • 状态枚举:如订单状态({ 1: '待支付', 2: '已发货' })。

二、字典的定义与管理方式

1. 组件内字典(局部字典)
  • 定义在 setupdata
    <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中,使用refreactive包装即可响应式;
    • 若通过app.config.globalProperties挂载全局字典,需注意:
      • 普通对象需用reactive包装(如app.config.globalProperties.$dict = reactive({}));
      • 数组类型字典需使用pushsplice等变异方法修改,或重新赋值整个数组。