【荐】Angular官方代码风格指南

本文为笔者对Angular官网风格指南的整理版本,删除/增加了部分内容。另外,原文对每个规范都作出了原因的解释,个别还有示例,需要的请点击查看原文。

原链接:英文文档中文文档

单一职责

单一文件

  • 一个文件定义一样东西,比如一个组件、一个服务、一个管道、一个指令
  • 每个文件最多不要超过400行

单一函数

  • 定义功能单一的函数
  • 一个函数最多不要超过75行

命名规范

  • 文件名采用feature.type.**,feature表示特性,type表示类型
    • 模块用 .module.ts
    • 路由模块用 -routing.module.ts
    • 组件用 .component.ts|html|css
    • 服务用 .service.ts
    • 管道用 .pipe.ts
    • 指令用 .directive.ts
    • 类型用 .model.ts
    • 数据用 .data.ts
  • 用”-“来分割单词,比如hero-list.component.ts
  • 单元测试文件名保持和测试对象一致,并以.spec.ts结尾
  • 端到端测试文件名保持和测试对象一致,并以.e2e-spec.ts结尾
  • 类名用大写驼峰规则,并且保持跟文件名的一致
    • 模块:比如app.module.ts定义的类名为AppModule
    • 路由模块:比如app-routing.module.ts定义的类名魏AppRoutingModule
    • 组件:比如hero-list.component.ts定义的类名为HeroListComponent
    • 服务:比如logger.service.ts定义的类名为LoggerService
    • 管道:比如address.pipe.ts定义的类名为AddressPipe
    • 指令:比如highlight.directive.ts定义的类名为HighlightDirective
    • 类型例外:按模块来划分,一个.model.ts定义多个类型
    • 数据:比如address-book.data.ts定义的变量名为addressBook
  • 脚本启动入口的文件名规定为main.ts,里面不包括任何业务逻辑,但要记得处理失败的情况
1
2
3
4
5
6
7
8
// main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.then(success => console.log(`Bootstrap success`))
.catch(err => console.error(err));
  • 指令选择器的命名采用小写驼峰规则,比如clickOutSide
  • 组件选择器的命名采用分隔符“-”连接小写字母的形式,比如hero-list

代码规范

  • 类命名采用大写驼峰规则
  • 常量定义用const,并且全部大写,如果有多个单词,用“_”连接,比如HERO_URL
  • 支持ES6的环境下,禁止使用var定义变量
  • 变量命名尽量控制在3个单词以内,有常见缩写形式的单词可采用缩写形式
  • 接口类型用大写驼峰规则,不建议以I为前缀,考虑用类代替接口
  • 属性和方法名用小写驼峰,私有属性和方法不建议以“_”为前缀
  • 建议用空一行的方式来区分第三方库的导入和项目本身文件的导入

项目结构

  • 好的项目结构的准则就是快速定位,快速识别,尽可能保持扁平,不要写冗余/重复代码
  • 把所有项目代码放入src文件夹,为每个特性创建文件夹
  • 第三方库放在src外的一个文件夹
  • 每个组件、服务、管道、指令都独成一个文件
  • 当组件有多个附属文件时(htm,css,ts,spec.ts),建议创建一个独立的文件夹

模块

  • 在src/app下创建根模块,建议命名为app.module.ts
  • 为每个特性创建一个模块,并且保持文件夹命名和模块命名一致
  • 共享模块建议用SharedModule命名,放在app/shared/shared.module.ts中
  • 在共享模块中定义复用的组件、指令和管道,避免在共享模块中定义服务
  • 在共享模块中导入所有必需的模块,比如CommonModule和FormsModule,导出所有复用的模块、组件、指令、管道
  • 考虑将只用一次的类放在核心特性模块中,并且仅在根模块中导入,建议写guard.ts来保证
  • 核心特性模块建议用CoreModule命名,放在app/core/core.module.ts中
  • 将单例服务放在核心特性模块中,比如ExceptionService和LoggerService
  • 在核心特性模块中导入所有必需的模块,比如CommonModule和FormsModule,导出所有定义的组件,服务等
  • 将全局仅用一次的组件放在核心特性模块,然后只在AppModule中导入,比如NavComponent和SpinnerComponent
  • 独立的特性模块可以做成懒加载模块,避免在任何地方导入懒加载模块,不然模块就会直接加载

组件

  • 当模板/样式超过3行时,写成单独文件
  • 删除无样式定义的样式文件
  • 模板/样式的定义与组件命名保持一致
  • 导入时使用相对路径
  • 用装饰器@Input和@Output来修改输入输出数据,而不是使用元数据中的inputs和outputs属性
  • 不推荐重命名输入输出数据
  • 按照变量,构造器,生命周期函数,一般方法的顺序定义;一般方法按页面的功能模块放一起,被调用的方法写在后面;变量和方法均先公有后私有排列;
  • 组件中只写跟视图相关的逻辑,把其他的业务逻辑放在服务中
  • 将可复用的业务逻辑放在服务中
  • 不推荐事件命名加上on前缀
  • 将展示逻辑放在组件的类中,而不是在模板中

指令

  • 当有跟模板无关的展示逻辑时,使用属性指令,比如[highlight]指令
  • 推荐使用@HostListener和@HostBinding,而不是元数据的host属性

服务

  • 保持单例服务的使用规则,服务用来在特性模块或者应用中共享数据和方法
  • 跟函数一样,一个服务只有一个目的
  • 把服务注入在最高层的组件/模块中,使得该单例服务能在子组件、子模块中共享
  • 使用@Injectable装饰服务类,而不是@Inject装饰参数
  • 跟数据相关的操作,比如xhr请求,本地储存等抽象成服务

生命周期

  • 需要生命周期钩子时,实现相关的接口,可有效防止错误

辅助工具

  • codelyzer来保持代码遵守该指南,当然你可以根据自己情况调整
  • 使用IDE的代码片段工具来快速生成具有一致性的代码片段,比如给VS Code安装snippets