通过学习mayfly-go,我学会了前端如何优雅设计字典值

shigen坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。 个人IP:shigen

shigen在假期的最后一天早晨起来,翻看了一下博客,一个mayfly-go的开源项目吸引了我的注意力,其实很久之前准备去啃它的,后来看到了代码就放弃了。现在正好有这个决心,打开了mayfly-go官网准备学习一番。发现官方给的更多的是展示的效果,没有详细的设计文档和技术文档,直到我我找到了mayfly-go的语雀文档,认真的研读了一番,最后在枚举值统一管理维护这一块看得我豁然开朗。因为在shigen之前的文章后段数据字典的优雅设计的文墨就提到了我的困惑,也接触了很多稀烂的项目,所以困惑更深,设篇文章的设计正好为我提供了一个巧妙的解决方案。于是,我花了一下午的时间来研究者问题,并写了如下的代码验证。

技术选型:Vue+typescript

字典,我相信对于开发者来说并不陌生。我就直接展开讲述。

设计反例

直接揉在代码里,最后代码就是一坨shi。

xml 复制代码
 <template>
   <div>
     <el-select v-model="type" placeholder="please select type">
       <el-option :key="1" label="菜单" :value="1"></el-option>
       <el-option :key="2" label="资源" :value="2"></el-option>
     </el-select>
     <p>type: {{ getTypeTag(type) }}</p>
   </div>
 </template>
 ​
 <script>
 export default {
   data() {
     return {
       type: 1,
     }
   },
   methods: {
     getTypeTag(type) {
       switch (type) {
         case 1: return "菜单";
         case 2: return "资源";
       }
     },
   }
 }
 </script>

无可否认,效果达到了。

但是,细细想一下,代码的维护起来,维护的成本不言而喻。

我就直接展示我借助【mayfly-go】获得的思路。

优雅设计

首先,我们提取枚举值,或者说字典值的共性:

typescript 复制代码
 export class TagType {
   type: string;
 }  

结合element-ui el-rag文档,我们标签或者按钮的类型只有几个固定的选项,primarysuccess,warring等等。所以,我们的标签类型只需要一个type字段,且约束为字符串类型。

对于字典值,我们抽象如下:

css 复制代码
 export interface EnumValue {
   value: any;
   label: string;
   type: TagType;
 }

一个标签,一个字典值,一个字典类型(可有可无)。抽象一下,就很好办了,我们有了对于字典定义和构造的能力了。

typescript 复制代码
 export class TagType {
   type: string;
 ​
   constructor(type: string) {
     this.type = type;
   }
 ​
   public static of(type = 'primary'): TagType {
     return new TagType(type);
   }
 ​
   public static tagTypeInfo(): TagType {
     return TagType.of('info');
   }
 ​
   public static tagTypeSuccess(): TagType {
     return TagType.of('success');
   }
 ​
   public static tagTypeDanger(): TagType {
     return TagType.of('danger');
   }
 ​
   public static tagTypeWarning(): TagType {
     return TagType.of('warning');
   }
 }
 ​
 export interface EnumValue {
   value: any;
   label: string;
   type: TagType;
 }
 ​
 export class EnumValue {
   value: any;
   label: string;
   type: TagType;
 ​
   constructor(value: any, label: string, type = TagType.of('primary')) {
     this.value = value;
     this.label = label;
     this.type = type;
   }
 ​
   public static of(value: any, label: string, type = TagType.of('primary')): EnumValue {
     return new EnumValue(value, label, type);
   }
 }  

第一次尝试写ts的模块化开发,还有点不习惯,毕竟脑子里还是Java。

OK,现在我们还需要在一堆同类型的字典中获得特定的字典,或者特定的字典属性。继续:

typescript 复制代码
   public static getEnumByValue(enumValues: EnumValue[], value: any): EnumValue | null {
     const enums = Object.values(enumValues);
     return enums.find(enumValue => enumValue.value === value) || null;
   }
 ​
   public static getLabelByValue<T extends EnumValue>(enumValues: T[], value: any): string {
     const enums = Object.values(enumValues);
     const enumValue = enums.find(enumItem => enumItem.value === value);
     return enumValue ? enumValue.label : '';
   }

这里,ES6的新语法安排上。

现在就是我们业务字段枚举的组装问题,快看看我的设计:

css 复制代码
 import { EnumValue, TagType } from "@/common/Enum";
 ​
 export const ResourceTypeEnum = {
   Menu: EnumValue.of(1, "菜单"),
   Resource: EnumValue.of(2, "资源"),
 }
 ​
 export const ResourceStatusTypeEnum = {
   Enable: EnumValue.of(true, "Enable", TagType.tagTypeSuccess()),
   Disable: EnumValue.of(false, "Disable", TagType.tagTypeDanger()),
 }

称不上优雅,但至少看起来简洁明了,容易理解。

在具体的页面上,我们只需要引入对应的资源即可。

xml 复制代码
 <template>
   <div>
     <h2>资源类型</h2>
     <el-select v-model="resourceType" placeholder="please select resouce type">
       <el-option v-for="(resourceType, index) in ResourceTypeEnum" :key="index" :label="resourceType.label"
         :value="resourceType.value"></el-option>
     </el-select>
     <p>label:{{ getLabelByValue(ResourceTypeEnum, resourceType) }}</p>
 ​
     <h2>资源类型状态</h2>
     <el-tag v-for="(status, index) in ResourceStatusTypeEnum" :key="index" :type="status.type.type"
       :value="resourceType.value"> {{ status.label }}
     </el-tag>
   </div>
 </template>
 ​
 <script>
 import EnumValue from '@/common/Enum';
 import { ResourceTypeEnum, ResourceStatusTypeEnum } from '@/views/system/enum';
 export default {
   data() {
     return {
       resourceType: 1,
       resourceTypeStatus: false,
       // 需要引入,避免报错undefined
       ResourceTypeEnum,
       ResourceStatusTypeEnum,
     }
   },
   methods: {
     getLabelByValue(enums, value) {
       return EnumValue.getLabelByValue(enums, value);
     }
   }
 }
 </script>

现在页面效果是这样的:

最大的优势就在于我在自己的页面代码看不到任何的字典设计和定义,完全是从一个文件中引入的。修改的话,只需要在enum.ts中修改即可。

当然,我印象中看到了有一种设计是把所有的字典值放在一个文件,如yaml文件中维护的。其实都是简化的方式,比传统的硬编码舒服多了。

与shigen一起,每天不一样!

相关推荐
Cachel wood11 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端12 分钟前
0基础学前端-----CSS DAY9
前端·css
joan_8516 分钟前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
m0_748236111 小时前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
Watermelo6171 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_748248941 小时前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_748235611 小时前
从零开始学前端之HTML(三)
前端·html
一个处女座的程序猿O(∩_∩)O3 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink6 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者8 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart