一、项目结构
开发过程中涉及的主要目录及用途如下;
- tests 测试用例,其内部目录结构与src文件夹保持一致
- docs 文档
- examples 网站示例
- src 开发目录
二、规范
1. 命名
文件夹与文件
名称全部使用小写,单词或分隔使用 - 符号,测试文件需要添加 -spec 标识
示例:
- index.ts
- basic-slider.ts
- number-spec.ts 测试文件
变量
首字母小写的驼峰命名法
示例
- lowercaseVaribaleName
常量
字母全部大写,单词之间使用下划线_分隔
示例
- CONSTANT_NAME
类型与接口
驼峰命名法
示例
- TypeName
类名
驼峰命名法
示例
- ClassName
2. 编码
整体编码规范见 JavaScript 编码规范
三、开发流程
1. 开发设计文档
正式组件开发之前,需要进行充分调研,包括但不限于 1. 参考现有组件缺点 2. 吸取同类组件优点 3. 创新性特性。最终形成开发设计【文档】, 文档需包括:
- 组件简介与描述
- 设计草图
- 引用方式
- 配置项
- 配置项名称
- 类型
- 默认值(若有)
- 描述
- 事件
- 事件名称
- 事件参数
- API
- 接口名称
- 参数列表及类型
- 返回值类型
- 交互
2. 评审
形成文档后,通知专家进行评审,评审考察点包括但不限于:
- 组件必要性、可用性
- 配置项、事件、API的完整性、必要性、命名合理性
- 交互设计的可用性
待评审通过后方可进入编码阶段
3. 编码
开发组件代码位于src/ui/目录,组件需根据其名称单独创建文件夹,内部至少包含入口文件index.ts,类型定义types.ts,可根据项目需要添加常量文件constant.ts,组件工具方法文件utils.ts以及子组件文件。
示例:(Slider)
- index.ts
- types.ts
- handle.ts 子组件
类型定义
首先根据开发设计文档中的配置项在types.ts中完成类型定义,常用的类型引用
// 图形配置项
import {
ShapeAttrs, // 基本图形配置项类型
DisplayObject, // 图形基类类型
DisplayObjectConfig, // 图形配置项类型
CircleProps, // 圆型配置项类型
EllipseProps, // 椭圆配置项类型
RectProps, // 矩形配置项类型
ImageProps, // 图片配置项类型
LineProps, // 线条配置项类型
PathProps, // 路径配置项类型
PolylineProps, // 多边形配置项类型
TextProps, // 文本配置项类型
Group, // 分组配置项类型
} from "../../types";
对于某些在不同状态下具有不同样式的图形,使用MixAttrs<>来定义其样式属性
// 带状态的文本样式
textStyle: MixAttrs<Partial<TextProps>>;
// 带状态的矩形样式
rectStyle?: MixAttrs<Partial<RectProps>>;
// 使用
textStyle:{
default: {} // 默认状态
active: {} // hover状态
disable: {} // 禁用状态
selected: {} // 选择状态
}
对于一个组件,其配置项包括两个部分
- 参数配置项 以【组件名Cfg】形式命名,其需要具有基本的图形属性。需要注释各配置项的作用
- 初始化配置项 以【组件名Options】命名,并使用参数配置项作为DisplayObjectConfig的泛型 ```typescript // Button types export type ButtonCfg = { x: number; y: number; // …配置项 }
// or // export interface ButtonCfg {}
export type ButtonOptions = DisplayObject
// Legend types
export type LegendBaseCfg = ShapeAttrs & {
// …配置项
}
export type LegendBaseOptions = DisplayObjectConfig
<a name="HJZro"></a>
#### 组件
绘制组件所使用的子组件、图形按需引入,[@antv/g](http://g-next.antv.vision/zh/docs/api/basic/display-object)提供了基本图形,也可以先自行封装然后引入。<br />组件类需继承自GUI类,且包含**组件tag**,**配置项默认值**、**构造方法**、**初始化方法、更新方法、事件绑定,**用到的子组件需定义为**类成员变量**
![](https://intranetproxy.alipay.com/skylark/lark/0/2021/jpeg/20156471/1629976260169-e8c64d37-4519-4109-b333-2e8d60416d42.jpeg)
> 为了方便组件更新,建议使用 getter 的方式来计算出绘制每个子图形、组件的属性,然后通过subShape.attr(cfg) 的形式应用属性
```typescript
// 以 Button 组件为例
export class Button extends GUI<Required<ButtonCfg>>{
public static tag = 'button'; // tag 名称全小写,单词使用 - 分隔
public static defaultOptions = {
type: Button.tag,
style:{
// 配置项默认值
}
}
private textShape!: Text;
private backgroundShape!: Rect;
private get textCfg() {} // 得到 textShape 配置项的 getter
private get backgroundCfg() {} // 得到 backgroundShape 配置项的 getter
constructor(options: ButtonOptions){
super(deepMix({}, Button.defaultOptions, options));
// do something others
}
// 初始化方法
public init() {}
// 更新方法
public update(cfg: Partial<ButtonCfg>){
// 根据需要使用 cfg
// this.attr(deepMix({}, this.attributes, cfg));
}
// 清理方法
public clear() {}
// 销毁方法
public destory() {
/**
* 1. 子组件销毁 可使用 this.removeChildren(true); 方法
*/
}
private initShape(){
// 初始化 textShape backgroundShape
}
// 事件回调方法
private eventCallback = (event) => {}
// 绑定事件
private bindEvents() {}
}
常用库方法
import {
clone, // 深度拷贝
clamp,
deepMix, // 递归合并两个Object
pick, // 从Object中根据name挑选值
throttle, // 节流
get, // 从Object中根据name获得值
min,
max,
minBy,
maxBy,
isArray,
isElement,
isFunction,
isNumber,
isString,
isUndefined,
} from "@antv/util";
3. 测试
使用jest框架进行单元测试,测试范围包括但不限于
- 子组件位置是否正确
- 样式是否生效
- 交互是否正常
- 事件能否触发
- 生命周期流程是否正常
- 方法输出是否正确
4. 使用文档
使用文档需包含
- 组件名称及介绍
- 引用方法
- 配置项名称、描述、类型及默认值
5. 网站示例
创建美观的组件示例,尽可能展现组件的各个形态与能力
6. 提交代码
提交代码前需通过ci,具体操作
npm run ci