快速手册-风格指南

风格指南:style guide

  • 单一职责

对所有的组件、服务等等应用单一职责原则 (SRP)。这样可以让应用更干净、更易读、更易维护、更易测试。
1.单组件文件非常容易阅读、维护,并能防止在版本控制系统里与团队冲突。
2.单组件文件可以防止一些隐蔽的程序缺陷,当把多个组件合写在同一个文件中时,可能造成共享变量、创建意外的闭包,或者与依赖之间产生意外耦合等情况。
3.单独的组件通常是该文件默认的导出,可以用路由器实现按需加载
4.最关键的是,可以让代码更加可复用、更容易阅读,减少出错的可能性。

  • 小函数

1.简单函数更易于阅读和维护
2.小函数可避免易在大函数中产生的隐蔽性错误,例如与外界共享变量、创建意外的闭包或与依赖之间产生意外耦合等。
3.单函数更易于测试,特别是当它们只做一件事,只为一个目的服务时。
4.简单函数促进代码重用

  • 总体命名原则

1.语义化
2.文件命名:推荐的模式为 feature.type.html|ts|scss。用点来分割
feature:功能描述。用横杠来分割单词
type:service、component、pipe、module、directive。

  • 组件选择器

1.坚持使用中线命名法(dashed-case)或叫烤串命名法(kebab-case)来命名组件的元素选择器。

 selector: 'toh-hero-button',

2.为组件添加自定义前缀

  • 指令选择器

1.坚持使用小驼峰形式命名指令的选择器。
2.为指令添加自定义前缀

selector: '[tohValidate]'
  • NgModule 命名

用cli默认生成的格式!eg:
坚持为 RoutingModule 类名添加 RoutingModule 后缀。
坚持为 RoutingModule 的文件名添加 -routing.module.ts 后缀。

  • 属性和方法

1.坚持使用小写驼峰命名法来命名属性和方法。
2.避免为私有属性和方法添加下划线前缀。
eg:避免:

private _toastCount: number;
  • 导入语句中的空行

1.坚持在第三方导入和应用导入之间留一个空行。eg:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { ExceptionService, SpinnerService, ToastService } from '../../core';
import { Hero } from './hero.model';
  • LIFT

坚持组织应用的结构,力求:快速定位 (Locate) 代码、一眼识别 (Identify) 代码、 尽量保持扁平结构 (Flattest) 和尝试 (Try) 遵循 DRY (Do Not Repeat Yourself, 不重复自己) 原则。

快速定位:坚持为每个特性区创建一个 NgModule(特性模块)。
一眼识别:语义化
扁平:考虑当同一目录下达到 7 个或更多个文件时创建子目录。

  • 共享特性模块

1.坚持在 shared 目录中创建名叫 SharedModule 的特性模块(例如在 app/shared/shared.module.ts 中定义 SharedModule)。
2.坚持在共享模块中声明那些可能被特性模块引用的可复用组件、指令和管道。
3.考虑 不要在共享模块中提供服务。服务通常是单例的,应该在整个应用或一个特定的特性模块中只有一份。
避免在 SharedModule 中指定应用级的单例服务提供商。如果是刻意要得到多个服务单例也行,不过还是要小心。
4.坚持在 SharedModule 中导入所有模块都需要的资产(例如 CommonModule 和 FormsModule)。

5.坚持在 SharedModule 中声明所有组件、指令和管道。
坚持从 SharedModule 中导出其它特性模块所需的全部符号。
为何? SharedModule 的存在,能让常用的组件、指令和管道在很多其它模块的组件模板中都自动可用。

  • 核心特性模块

1.坚持在 core 目录下创建一个名叫 CoreModule 的特性模块(例如在 app/core/core.module.ts 中定义 CoreModule)。
2.考虑把那些数量庞大、辅助性的、只用一次的类收集到核心模块中,让特性模块的结构更清晰简明。

坚持把那些“只用一次”的类收集到 CoreModule 中,并对外隐藏它们的实现细节。简化的 AppModule 会导入 CoreModule,并且把它作为整个应用的总指挥。

坚持把应用级、只用一次的组件收集到 CoreModule 中。 只在应用启动时从 AppModule 中导入它一次,以后再也不要导入它(例如 NavComponent 和 SpinnerComponent)。
为何?真实世界中的应用会有很多只用一次的组件(例如加载动画、消息浮层、模态框等),它们只会在 AppComponent 的模板中出现。 不会在其它地方导入它们,所以没有共享的价值。 然而它们又太大了,放在根目录中就会显得乱七八糟的。

3.坚持把要共享给整个应用的单例服务放进 CoreModule 中(例如 ExceptionService 和 LoggerService)。
4.坚持导入 CoreModule 中的资产所需要的全部模块(例如 CommonModule 和 FormsModule)。
5.避免在 AppModule 之外的任何地方导入 CoreModule。

  • 防止多次导入 CoreModule

1.应该只有 AppModule 才允许导入 CoreModule。

2.坚持防范多次导入 CoreModule,并通过添加守卫逻辑来尽快失败。

为何?守卫可以阻止对 CoreModule 的多次导入。

为何?守卫会禁止创建单例服务的多个实例。

  • 把组件当做元素

考虑给组件一个元素选择器,而不是属性或类选择器。
为何?查看组件模板的 HTML 时,更容易识别一个符号是组件还是指令。

  • 把模板和样式提取到它们自己的文件

1.坚持当超过 3 行时,把模板和样式提取到一个单独的文件。
2.坚持指定相对于模块的 URL ,给它加上 ./ 前缀。

  • 内联输入和输出属性装饰器

1.坚持 使用 @Input() 和 @Output(),而非 @Directive 和 @Component 装饰器的 inputs 和 outputs 属性:
2.坚持把 @Input() 或者 @Output() 放到所装饰的属性的同一行。

  • 避免为输入和输出属性指定别名

1.避免除非有重要目的,否则不要为输入和输出指定别名。eg:
避免:

 @Output('changeEvent') change = new EventEmitter<any>();
  @Input('labelAttribute') label: string;
  • 成员顺序

1.坚持把属性成员放在前面,方法成员放在后面。
2.坚持先放公共成员,再放私有成员,并按照字母顺序排列。

eg:

  // public properties
  message: string;
  title: string;
 
  // private fields
  private defaults = {
    title: '',
    message: 'May the Force be with you'
  };

  // public methods
  activate(message = this.defaults.message, title = this.defaults.title) {
    this.title = title;
    this.message = message;
    this.show();
  }
 
  // private methods
  private hide() {
    this.toastElement.style.opacity = 0;
    window.setTimeout(() => this.toastElement.style.zIndex = 0, 400);
  }
 
  • 把逻辑放到服务里

坚持在组件中只包含与视图相关的逻辑。所有其它逻辑都应该放到服务中。

坚持把可重用的逻辑放到服务中,保持组件简单,聚焦于它们预期目的。
eg:
ajax的一些处理逻辑放出去,我只是调用接口就ok了!

  • 不要给输出属性加前缀

坚持命名事件时,不要带前缀 on。

坚持把事件处理器方法命名为 on 前缀之后紧跟着事件名。
eg:

<toh-hero (savedTheDay)="onSavedTheDay($event)"></toh-hero>
  • 把表现层逻辑放到组件类里

坚持把表现层逻辑放进组件类中,而不要放在模板里。

为何?逻辑应该只出现在一个地方(组件类里)而不应分散在两个地方。

为何?将组件的表现层逻辑放到组件类而非模板里,可以增强测试性、维护性和重复使用性。

eg:
error:

<div>
 	Average power: {{totalPowers / heroes.length}}
</div>

ok:

<div>
 	Average power: {{avgPower}}
</div>
// ts:
  get avgPower() {
    return this.totalPowers / this.heroes.length;
  }

  • 使用指令来增强已有元素

坚持当你需要有表现层逻辑,但没有模板时,使用属性型指令。

为何?属性型指令没有模板。

为何?一个元素可以使用多个属性型指令。

@Directive({
  selector: '[tohHighlight]'
})
export class HighlightDirective {
  @HostListener('mouseover') onMouseEnter() {
    // do highlight work
  }
}


// html:
<div tohHighlight>Bombasta</div>

HostListener 和 HostBinding 装饰器 vs. 组件元数据 host

考虑优先使用 @HostListener 和 @HostBinding,而不是 @Directive 和 @Component 装饰器的 host 属性。

坚持让你的选择保持一致。

import { Directive, HostBinding, HostListener } from '@angular/core';

@Directive({
  selector: '[tohValidator]'
})
export class ValidatorDirective {
  @HostBinding('attr.role') role = 'button';
  @HostListener('mouseenter') onMouseEnter() {
    // do work
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值