Angular 组件库 NG-NEST 源码解析:项目结构

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 文件样式中调用。

总结

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

阅读 1.4k
4 声望
1 粉丝
0 条评论
你知道吗?

4 声望
1 粉丝
宣传栏