① 项目介绍
项目的安装与初始化请先查看宿主项目
https://gitee.com/hamm/AirPowerDemo
为了满足前端开发标准化、工程化、系统化等等需求,我们设计并开发了一个开发组件库和常用类库和方法库的集合基础脚手架,其中包含了一些页面通用的布局、常用的弹窗和交互、提示信息以及网络请求,强类型面向对象的约束规范等,以满足日常开发的快捷、稳健、标准化等要求。
② 项目依赖
AirPower 目前依赖 Vue + TypeScript + Element Plus + class-transformer 等组件,其中还包含了一些第三方模块的依赖,具体可以参考项目的 package.json。
③ 模块说明
AirPower 内置了以下一些模块:
-
component组件包含了常用的
AInputAButtonATableAToolBarAPage等常用的组件; -
config配置包含了 实体配置、字段在
TableSearchForm中的特性配置、Props传参配置、图像配置等常用的配置类、配置方法等; -
decorator装饰器:提供了表格配置、表单配置、类和属性自定义名称配置、搜索配置等装饰器;
-
dto数据传输模型包含了一些分页、排序、常用类、抽象基类等标准的数据传输模型;
-
enum枚举提供了目前已经达成标准和规范的一些枚举信息,如颜色、日期格式、反馈图标样式、搜索类型、HTTP 参数等;
-
feedback反馈基于
Element Plus提供的标准反馈组件,定义了规范的一些弹窗、确认框、通知信息等反馈组件; -
helper助手类提供了时间日期、文件、数据转换、弹窗、随机与加解密、路由等快捷操作的助手类和方法;
-
interface接口提供了一些常用数据结构的标准化配置以及需要被实现的标准接口;
-
model数据模型提供一些基础的数据模型与操作方法;
-
service服务提供了一些基础的
CRUD方法的基础网络请求服务和一些常用的API; -
view 页面
提供了错误页等常用的内置页面;
④ 开发理念
-
CaaS配置即服务为了避免大量重复代码的出现,我们尽可能通过
TypeScript的装饰器将一些类或属性的配置写入到原型链中,在需要使用这些配置的地方通过反射将保存的参数配置取出使用即可。其中,如果涉及一些默认值,将默认值通过
AirConfig作为基础配置进行初始化到系统中,通过配置项的使用范围和配置成本进行调整后,使用方可以最小配置的方式进行系统业务的接入和开发。 -
强面向对象的支持
在相同或相似业务中,我们使用标准的强面向对象进行实现,基于继承、封装等特性进行代码的复用,通过泛型、接口等方式将相似的业务逻辑进行标准化约束,实现相似但又不完全相同的一些灵活业务的快速开发。
-
数据和类的转换器
为了在后端因业务要求进行属性调整后前端不需要做大量的查找替换进行修复,我们引入了
class-transformer这个第三方库进行数据转换,通过自由选择Expose字段和配置转换规则来实现仅在配置层即可解决字段属性变更的问题。详细请阅读关于数据转换的部分。
⑤ 设计要点
-
1️⃣ TypeScript 装饰器篇
装饰器是 TypeScript 引入类似
Java 注解的一个编程方式,依赖装饰器,可无侵入式的在业务前后运行其他的业务代码而无需改动原有的业务代码。装饰器的本质就是一个
Function类、方法、属性、参数等在标记了装饰器后,会执行装饰器的相关方法,然后通过原型链或者反射的方式,对操作的对象进行一些数据的处理或逻辑的限制。 -
AirPower 使用的普通装饰器
@ClassName('用户') //为类标记一个可读的名称 @FieldName('真实姓名') //为属性标记一个可读的名称 @Description('这是用户的名称') //为属性标记一个可读的描述标记了
ClassNameFieldNameDescription装饰器的类或属性,可使用类的原型或者类的对象进行获取使用场景介绍
当我们需要频繁的修改某些实体的名字,如
AppEntity从 应用 改为 应用程序,姓名改为真实姓名,我们往往需要去查找替换,所以我们直接标记到对应的AppEntity类上,其他地方统一从实体中直接获取。 -
AirPower 使用的表格配置装饰器
@TableField() //为实体类的属性标记 是否为表格使用的字段TableField注解支持传入一个ITableFieldConfig接口约束下的 JSON 配置项,可对表格的列名称、宽度、是否自定义列、是否枚举列等进行一系列的配置。使用时,可通过类的原型或类的对象进行读取并传入给
ATable组件。获取方法如下:UserEntity.prototype.getTableFieldConfigList() //或者 const user = new UserEntity() user.getTableFieldConfigList() //用户列表的表格显示字段配置信息数组 -
AirPower 使用的搜索配置装饰器
@SearchField() //为实体类的属性标记 是否为搜索使用的字段SearchField注解支持传入一个ISearchFieldConfig接口约束下的JSON配置项,可对搜索的输出 key 、是否枚举列等进行一系列的配置。使用时,可通过类的原型或类的对象进行读取并传入给
AToolBar组件。获取方法如下:UserEntity.prototype.getSearchFieldConfigList() //或者 const user = new UserEntity() user.getSearchFieldConfigList() //用户搜索字段配置信息数组 -
AirPower 使用的表单配置装饰器
@FormField() //为实体类的属性标记 是否为表单使用的字段FormField注解支持传入一个IFormFieldConfig接口约束下的JSON配置项,可对搜索的输出 key 、是否枚举列等进行一系列的配置。使用时,可通过类的原型或类的对象进行读取并传入给
AInput组件。获取方法如下:<AInput v-model.name="user.name" :entity="UserEntity"/> -
2️⃣ 数据转换篇
-
class-transformer 简介
在日常的 API 接口对接过程中,接口中难免产生很多无用的属性,亦或者某些属性需要前端进行转换后才能使用,
AirPower采用了 类 +class-transformer库来完成前端和后端的接口数据处理。class-transformer是TypeScript下一个基于装饰器+Reflect-metadata实现的一个数据转换库,能根据实体属性上标记的相关装饰器规则进行类到 JSON、JSON 到类的转换,具体的相关操作文档可以查看npm-class-transformer -
class-transformer 的装饰器
//将 userName 属性暴露为 username 来处理后端和前端字段不统一的问题 @Expose({name:"username"}) userName!: string; //标记属性不被来去转换 AirModel 中配置必须 Expose 所以这个一般很少使用 @Exclude() password //标记属性必须被转为什么类型 支持简单类型 复杂类型 @Type(()=>String) password //自定义转换规则 可在指定的转换方向上进行数据的转换 //如时间戳转可视化时间等操作 @Transform(({value}) => { // custom transform code here return something; },{ toClassOnly | toPlainOnly : boolean })当然, 我们将
class-transformer和Reflect-metadata进行了一系列的封装, 请看下面的内容. -
AirClassTransformerHelper 转换助手类
我们将上面的两个库进行了更适合我们的业务封装, 实现了
AirClassTransformerHelper一系列的装饰器和反射高级编程的功能.其中提供了两个静态方法:
// 将普通的 JSON 对象转换到声明的实体类中, 方便字段的调用和数据转换 AirClassTransformerHelper.parse() // 将一个对象拷贝到一个新的对象上, 避免深浅拷贝的尴尬 AirClassTransformerHelper.copy() -
3️⃣ 面向对象篇
-
AirModel 基础模型类
AirModel是AirPower中通过class-transformer库 实现了json 到类互相转换的一系列方法的一个数据模型基类。 我们建议,所有与后端对接的数据类都必须根继承至AirModel, 比如数据实体分页对象搜索对象等等。然后你就可以通过class-transformer提供的相关装饰器对指定数据类进行字段的暴露、转换等操作。 -
AirEntity 实体基类
AirEntity约束子类必须包含ID字段,请自行实现一个继承AirEntity实体基类的BaseEntity来进行比选字段的暴露和配置,也可以在BaseEntity中添加子系统业务相关的其他必须的业务字段。 -
使用面向对象继承减少重复接口的声明
我们在
AirPower里实现了一个AirAbstractService服务基类,实现了单表增加、删除、修改、查询分页、查询数组等相关基础方法,业务中如无特殊业务需求,无需再次实现单表业务中这些重复的方法,但我们建议:宿主初始化一个继承了AirAbstrtactService的中间基类BaseService以应对不符合 AirPower 规范的场景,你可以在BaseService中间接口类中重写相关的接口。 -
在合理的场景下使用
interface作为数据结构interface在面向对象中可作为约束来对业务进行规范,但TypeScript很多使用者都习惯使用interface来作为限制对象属性的工具,我们建议:
只在装饰器参数、与第三方库的数据转换场景下使用
interface作为数据格式的直接限制使用,其他任何场景不使用interface作为直接限制。
通过 Demo 宿主项目来体验一把
使用说明
我们使用的是 Vite 构建, 包管理使用的是 yarn, 请先安装前叙的相关工具后继续接下来的操作 :)
核心包仓库: https://gitee.com/hamm/airpower
一、初始化仓库(推荐 ssh)
建议 windows 开发者使用
git bash不要使用 windows 自带的拉垮的cmdpowershell等。否则接下来的脚本可能出现问题,你只能通过自己手动去操作。
任选一个方式的脚本一键初始化项目
- ssh 方式
git clone [email protected]:hamm/AirPowerDemo.git &&
cd AirPowerDemo/src &&
git clone [email protected]:hamm/airpower.git && cd ../ &&
yarn && cp .env.dev .env && yarn s
- https 方式
git clone https://gitee.com/hamm/AirPowerDemo.git &&
cd AirPowerDemo/src &&
git clone https://gitee.com/hamm/airpower.git && cd ../ &&
yarn && cp .env.dev .env && yarn s
二、修改环境变量
按需修改配置
VITE_APP_NAME = "开发环境"
VITE_APP_API_URL = "/api/"
VITE_APP_STATIC_URL = "/static/"
三、启动和打包
启动项目前,我们建议你关闭 visual studio code 的 Vetur 插件,避免 vue2 和 vue3 产生冲突。
# 启动项目
yarn s #缩写指令
# 打包项目
yarn dev #开发环境 使用.env.dev
yarn test #测试环境 使用.env.test
yarn production #生产环境 使用.env.production
四、其他命令
#使用标准 commit 模板
yarn c
#更新项目和 AirPower
yarn u
#查看 Git 格式化日志
yarn l
五、推荐的 VSCODE 插件扩展
- TypeScript Vue Plugin (Volar)
- Vue Language Features (Volar)
- ESLint
- SCSS Formatter
如碰到其他兼容问题,建议在工作区禁用以上四个插件之外的其他插件,特别是
Vetur。