(参考Angular官方文档中的风格指南,详细信息可在https://angular.cn/guide/styleguide中查看.)
编写目的:
1.使用统一的编码规范是使应用程序的结构和编码风格标准化,以便于阅读和理解这段编码。
2.好的编码约定可使代码严谨,可读性强且意义清楚,并且尽可能直观。
适用范围:
1.本文档主要为前端Angular开发语言的规范,不适用于其他语言规范.
2.适用人员:所有开发人员。
具体编码规范:
1. 单一职责:
坚持每个文件只定义一样东西(例如:模块,路由,组件,服务,基类等)。
2. 总体命名:
坚持所有符号使用一致的命名规则,遵循同一个模式来描述符号的特性和类型,模式为feature.type.ts.
使用点和横杠来分割文件名(用’-’来分割单词,用’.’来分割类型,例如:index-routing.module.ts) 。
坚持在符号名后面追加约定的类型后缀(例如.component.ts、.directive.ts、.module.ts、.pipe.ts、.service.ts)。
指令选择器: 坚持使用小驼峰命名法来命名指令的选择器(防止与html名字冲突,指令更加容易被识别)。
管道名: 坚持为所有管道使用一致的命名约定,用它们的特性来命名。
Angular NgModule 命名: 坚持为文件名添加.module.ts扩展名。
坚持为 RoutingModule 类名添加RoutingModule后缀。
坚持为 RoutingModule 的文件名添加-routing.module.ts后缀。
3. 编程约定:
坚持一致的编程、命名和空格的约定。
类: 坚持使用大写驼峰命名法来命名类。
常量: 坚持用const声明变量,除非它们的值在应用的生命周期内会发生变化。(HERO_ROUTES)
接口: 坚持使用大写驼峰命名法来命名接口。
属性和方法: 坚持使用小写驼峰命名法来命名属性和方法。
避免为私有属性和方法添加下划线前缀。(private _toastCount: number;)
导入语句中的空行: 坚持在第三方导入和应用导入之间留一个空行。
4. 应用程序结构与 Angular 模块
所有应用程序的源代码都放到名叫src的目录里。
所有特性区都在自己的文件夹中,带有它们自己的 Angular 模块。
所有内容都遵循每个文件一个特性的原则。每个组件、服务和管道都在自己的文件里。
所有第三方程序包保存到其它目录里,而不是src目录。
你不会修改它们,所以不希望它们弄乱我们的应用程序。
定位:
坚持直观、简单和快速地定位代码。
为何? 要想高效的工作,就必须能迅速找到文件,特别是当不知道(或不记得)文件名时。 把相关的文件一起放在一个直观的位置可以节省时间。 富有描述性的目录结构会让你和后面的维护者眼前一亮。
识别:
坚持命名文件到这个程度:看到名字立刻知道它包含了什么,代表了什么。
坚持文件名要具有说明性,确保文件中只包含一个组件。
避免创建包含多个组件、服务或者混合体的文件。
扁平: 坚持尽可能保持扁平的目录结构。
考虑当同一目录下达到 7 个或更多个文件时创建子目录
按特性组织的目录结构: 坚持根据特性区命名目录。
共享特性模块:
在shared目录中创建名叫SharedModule的特性模块
在共享模块中声明那些可能被特性模块引用的可复用组件、指令和管道。
考虑把可能在整个应用中到处引用的模块命名为SharedModule
避免在共享模块中提供服务。服务通常是单例的,应该在整个应用或一个特定的特性模块中只有一份。
坚持在SharedModule中导入所有模块都需要的资产(例如CommonModule和FormsModule)。
避免在SharedModule中指定应用级的单例服务提供商。如果是刻意要得到多个服务单例也行,不过还是要小心。(惰性加载的特性模块如果导入了这个共享模块,会创建一份自己的服务副本,这可能会导致意料之外的后果。
为何?对于单例服务,你不希望每个模块都有自己的实例。 而如果SharedModule提供了一个服务,那就有可能发生这种情况。)
核心特性模块
考虑把那些数量庞大、辅助性的、只用一次的类收集到核心模块中,让特性模块的结构更清晰简明。
坚持把那些“只用一次”的类收集到CoreModule中,并对外隐藏它们的实现细节。简化的AppModule会导入CoreModule,并且把它作为整个应用的总指挥。
坚持在core目录下创建一个名叫CoreModule的特性模块(例如在app/core/core.module.ts中定义CoreModule)。
坚持把要共享给整个应用的单例服务放进CoreModule中(例如ExceptionService和LoggerService)。
坚持导入CoreModule中的资产所需要的全部模块(例如CommonModule和FormsModule) 坚持把应用级、只用一次的组件收集到CoreModule中。
只在应用启动时从AppModule中导入它一次,以后再也不要导入它(例如NavComponent和SpinnerComponent)。
避免在AppModule之外的任何地方导入CoreModule。
坚持从CoreModule中导出AppModule需导入的所有符号,使它们在所有特性模块中可用。
防止多次导入CoreModule
应该只有AppModule才允许导入CoreModule。
坚持防范多次导入CoreModule,并通过添加守卫逻辑来尽快失败(阻止)。
惰性加载的目录
某些边界清晰的应用特性或工作流可以做成惰性加载或按需加载的,而不用总是随着应用启动。
坚持把惰性加载特性下的内容放进惰性加载目录中。
典型的惰性加载目录包含路由组件及其子组件以及与它们有关的那些资产和模块。
永远不要直接导入惰性加载的目录
避免让兄弟模块和父模块直接导入惰性加载特性中的模块。(还会出现跳过子路由的异常情况!!!)
5. 组件
组件选择器命名:
坚持使用中线 (dashed) 命名法或烤串 (kebab) 命名法来命名组件中的元素选择器。
把组件当做元素:
考虑给组件一个元素选择器,而不是属性或类选择器。
把模板和样式提取到它们自己的文件:
坚持当超过 3 行时,把模板和样式提取到一个单独的文件。
坚持把模板文件命名为[component-name].component.html,其中,[component-name] 是组件名。
内联输入和输出属性装饰器:
坚持把@Input()或者@Output()放到所装饰的属性的同一行。(易于识别)
避免为输入和输出属性指定别名:
避免除非有重要目的,否则不要为输入和输出指定别名。(同一个属性有两个名字(一个对内一个对外)很容易导致混淆。)
成员顺序:
坚持把属性成员放在前面,方法成员放在后面。
坚持先放公共成员,再放私有成员,并按照字母顺序排列。
把逻辑放到服务里:
坚持在组件中只包含与视图相关的逻辑。所有其它逻辑都应该放到服务中。
坚持把可重用的逻辑放到服务中,保持组件简单,聚焦于它们预期目的。(便于复用,测试,解除依赖)
6. 指令
使用指令来增强已有元素:
坚持当你需要有表现层逻辑,但没有模板时,使用属性型指令。
7. 服务
服务总是单例的:
坚持在同一个注入器内,把服务当做单例使用。用它们来共享数据和功能。
提供一个服务:
坚持将服务提供到共享范围内的顶级组件的 Angular
注入器。(当不同的两个组件需要一个服务的不同的实例时,上面的方法这就不理想了。在这种情况下,对于需要崭新和单独服务实例的组件,最好在组件级提供服务。)
使用 @Injectable() 类装饰器:
坚持当使用类型作为令牌来注入服务的依赖时,使用@Injectable()类装饰器,而非@Inject()参数装饰器。
8. 数据服务
通过服务与 Web 服务器通讯:
坚持把数据操作和与数据交互的逻辑重构到服务里。
坚持让数据服务来负责 XHR 调用、本地储存、内存储存或者其它数据操作。
组件的职责是为视图展示或收集信息。它不应该关心如何获取数据,它只需要知道向谁请求数据。把如何获取数据的逻辑移动到数据服务里,简化了组件,让其聚焦于视图。 数据管理的详情,比如头信息、方法、缓存、错误处理和重试逻辑,不是组件和其它的数据消费者应该关心的事情。