乐趣区

Angular-组件库-NGNEST-源码解析项目结构

前言

从本文开始将逐步介绍 NG-NEST UI 库的项目源码结构和组件是如何设计制作的。

环境准备

通过以下命令来下载 ng-nest 源码:

$ git clone https://github.com/NG-NEST/ng-nest.git
$ cd ng-nest
$ npm install

核心目录介绍

| 文件夹名称 | 说明 | 
| docs | 非组件文档,项目简介、快速上手、教程等 |
| lib | 组件文件夹,包含框架组件源码 |
| scripts | ts 脚本,主要用来生成文档页面组件以及相关的路由配置 |
| src | 文档项目,生成的文档会自动放到 src/main/docs 下 |

package.json 文件中的 scripts 说明

...
"scripts": {
    "ng": "ng",
    "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points",  // 加快 ngcc 编译
    "start": "ng serve", // 启动文档项目
    "start:en": "ng serve --configuration=en",
    "start:zh": "ng serve --configuration=zh",
    "build": "node --max_old_space_size=81920 ./node_modules/@angular/cli/bin/ng build --prod",  // 打包文档项目
    "build:en": "ng build --prod --configuration=production-en", 
    "build:zh": "ng build --prod --configuration=production-zh",
    "build:ng-nest-ui": "node --max_old_space_size=81920 ./node_modules/@angular/cli/bin/ng build ng-nest-ui --prod && npm run build:scss", // 打包组件库并拷贝相关 scss 样式文件
    "build:docs": "npm run build:scripts && node ./scripts/build/generate/docs", // 生成文档页面
    "build:scripts": "tsc -p scripts", // ts 脚本编译成 js
    "build:scss": "cpx ./lib/ng-nest/ui/style/**/* ./dist/ng-nest/ui/style",  // 拷贝组件库样式文件
    "test": "ng test ng-nest-site", // 测试文档项目
    "test:ng-nest-ui": "ng test ng-nest-ui", // 组件测试,通过此处开发测试单个组件
    "lint": "ng lint",
    "e2e": "ng e2e",
    "extract": "ng xi18n --output-path=locale" // 文档项目的本地化配置
},
...

组件结构

我们以 Button 组件来介绍一下组件的结构,所有组件的结构都是遵循此格式。

lib/ng-nest/ui/button
├── examples                        示例代码,组件的示例说明通过此处生成
├── style                           样式 @mixin 和 样式参数定义
├── button.component.html           
├── button.component.scss
├── button.component.spec.ts        测试文件,测试模式下直接访问对应的关键子调试单个组件
├── button.component.ts
├── button.module.ts                组件模块,声明模块中的视图,依赖的模块,以及导出的视图
├── button.property.ts              组件属性(Input 输入和 Ouput 输出参数),以及相关的类型定义,文档中的组件参数说明通过此处生成
├── buttons.component.scss
├── buttons.component.ts
├── index.ts
├── package.json                    ng-packagr 配置,单独引入组件
├── public-api.ts                   导出所有当前组件中的 class 文件
└── readme.md                       组件文件以及 API

Core 文件夹

lib/ng-nest/ui/core 文件夹主要用来定义公共的函数、接口、动画、服务等,如 Checkbox 组件中的 checkbox.property.ts:

...
/**
 * Checkbox Property
 */
@Component({template: ''})
export class XCheckboxProperty extends XControlValueAccessor<boolean | Array<any>> implements XCheckboxOption {
  /**
   * 多选框数据
   */
  @Input() @XDataConvert() data: XData<XCheckboxNode> = [];
  /**
   * 按钮样式
   */
  @Input() @XInputBoolean() button: XBoolean;
  ...
}

XControlValueAccessor 是一个表单的抽象泛型类,boolean | Array<any> 表示控件 ngModel 中绑定的值可能是 boolean(data 为单个值)或者 Array 数组(data 为多个值),其中还定义了表单通用属性以及方法,并实现了 Angular 中做自定义表单控件需要的接口 ControlValueAccessor:

export abstract class XControlValueAccessor<T> extends XFormProp implements ControlValueAccessor {
  ...
  value: T;
  onChange: (value: T) => void;
  onTouched: () => void;
  writeValue(value: T): void {this.value = value;}
  registerOnChange(fn: (value: T) => void): void {this.onChange = fn;}
  registerOnTouched(fn: () => void): void {this.onTouched = fn;}
  setDisabledState(disabled: boolean) {this.disabled = disabled;}
  ...
}

data 属性前面的 @XDataConvert() 是一个数据转换的装饰器,Checkbox 的选项数据可以支持以下任意一种格式(最终都被转换成统一的格式):

dataOne = ['QQ', '微信', '钉钉', '微博'];
dataTwo = ['QQ', '微信', { label: '钉钉', disabled: true}, '微博'];
dataThree = [{ label: 'QQ', icon: 'ado-qq'},
  {label: '微信', icon: 'ado-wechat'},
  {label: '钉钉', icon: 'ado-dingding'},
  {label: '微博', icon: 'ado-weibo'}
];
dataFour = new Observable((x) => {
  // 替换成 http 请求,或者 data 直接定义成 Observable 对象
  x.next(['QQ', '微信', '钉钉', '微博']);
  x.complete();});

data 属性的类型 XData<XCheckboxNode> 是一个联合类型,通过 XData<T> 来定义:

// 数据类型
export type XData<T> = T[] | Observable<T[] | any[]> | any[] | Function;

button 属性前面的 @XInputBoolean() 装饰器主要是使组件支持以下的写法,可以省略传入 true 值(写了属性,没有传入值默认转换成 true):

<x-checkbox [data]="data" button></x-checkbox>

Core 文件夹里面还封装了 Angular 官方的 HttpClient 请求、路由复用的配置、localStorage 和 sessionStorage 服务、树结构的类型定义等等。

Style 文件夹

lib/ng-nest/ui/style 定义公共的 @mixin 和参数,并把 css3 中的 var 参数关联到 scss 的变量中,然后各个组件的 style 文件样式中调用。

总结

通过以上内容我们对整个项目有了一个大致的了解,由于单个组件的内容是集中的,模板、示例、样式、配置、测试、文档等,我们可以很容易的处理组件问题。之后会逐步从简单的组件切入,带领大家去体验如何设计制作组件。

退出移动版