针对 Angular 的自以为是的编码风格指南,使用正确的工具补充正确的风格指南。

2025-06-04

Angular 的编码风格指南

使用正确的工具来补充正确的风格指南。

编写代码的内部风格指南是一个重要的决定,任何开发团队都应该在某个时候(最好是在项目早期)定义并达成一致。

本文最初Giancarlo Buomprisco在Bits and Pieces上发表

如果你一直从事专业代码编写,你就会非常清楚代码风格对很多开发人员来说有多么重要。在我的职业生涯中,无数的时间都花在了代码风格上。

但为什么它如此重要呢?程序员阅读代码的次数远多于编写代码的次数:我们必须尽可能简化这项任务,这对于我们自己,尤其是我们的队友来说至关重要。

共识是在编写第一行代码之前定义一个样式指南,但这不应该在整个项目生命周期中固定下来:它是从实验和经验中得出的一系列连续的学习。

这也不意味着你应该每天改变主意:这意味着你应该随着项目的发展与你的团队一起评估、讨论和决定。

从 alpha 版本开始编写 Angular 应用程序后,我已经形成了自己的风格,受到与我共事的人的强烈影响,阅读了很多人的代码,并简单地尝试了我的项目。

在本文中,我想展示我如何设计我的 Angular 应用以及这些设计背后的原理。希望它能启发你和你的团队采用其中的一些方法,或者创建你自己的 Angular 应用。

我们非常欢迎任何有关如何改进它的建议!

注意:本风格指南仅提供风格方面的指导,并非基于技术细节和最佳实践。本风格指南旨在提升代码的美观性和可读性,而非性能、设计模式或其他方面。


使用正确的工具来补充正确的风格指南。

除了遵循特定的代码风格指南之外,使用一些工具来简化代码的理解、维护和复用(供组织内部人员甚至开源社区使用)也很重要。我最喜欢使用的一个工具是Bit.dev

HTML 换行和排序

Angular 模板在普通 HTML 上添加了相当多的语法,有时它们不太容易阅读。

我的第一个建议是关于换行的。我通常不会让所有文件每列超过 80 个字符:因为垂直阅读比水平阅读更容易。

这是一个没有任何约定的元素:

乱糟糟的,是不是?我做咨询的时候,几乎每个项目都是这么写的。

我们将使用一组简单的规则重写上面的代码片段,使其更具可读性。

定义编写 HTML 标签的规则

  • 当一个元素有两个或多个属性时,我通常每行只写一个属性

  • 属性必须按照特定顺序书写

  • 除非使用单个属性,否则结束标记必须写在下一行

我建议定义一个特定的顺序:

  • 结构指令

  • 动画

  • 静态属性

  • 动态属性

  • 活动

让我们看一个例子来了解我个人如何编写前面的例子:

更好的是,我总是将结构指令专门与 ng-container 一起使用:

虽然我认为你可以根据主观观点来混合属性的顺序,但我强烈认为应该先显示结构指令

结构指令告诉我(在我需要知道它所做的任何事情之前):

  • 这个字段会显示吗?为什么?

  • 这个字段是否重复?

在我看来,这有助于阅读和理解模板的结构。

管道

管道非常强大:它们可以转换模板中的值,并避免组件中的重复/逻辑。它们可以轻松重用和混合,并且易于编写。

但它们容易阅读和识别吗?是的,也是不的。

这非常主观,而且只是个小问题,但我仍然认为值得分享:每当我在模板中看到管道时,我都会倾向于用括号将它们括起来。括号带来的除法感让我知道值正在被转换,而且通常更容易看清:

当使用多个管道时,这可能更为重要:

生命周期钩子

接口

添加生命周期钩子接口不是强制性的,而是一种建议的做法,我强烈建议遵循。

命令

当我寻找生命周期钩子时,我通常会直接查看构造函数,并希望它们能够同时出现,而不会与其他类方法混淆。理想情况下,它们的定义顺序应该与执行顺序相同。

我的建议是:

  • 总是添加接口

  • 在构造函数上方添加公共和私有属性

  • 在构造函数下方和组件方法上方添加方法

  • 将它们全部添加到彼此靠近的位置

  • 按执行顺序添加它们。诚然,这有点难以始终如一地遵循,所以我想这是最不重要的一点

逻辑

我通常避免在生命周期钩子中直接编写任何逻辑:我的建议是将逻辑封装在私有方法中并在生命周期钩子中调用它们:

组件属性和方法

Angular 使用装饰器来修饰组件的方法和属性,以增强其功能。

它们的数量太多了,以至于定义一个要遵循的特定顺序会很困难,但我尝试遵循的重要一点是将具有相同装饰器的属性和方法彼此靠近。

以下是我认为不好的例子:

下面是我编写的方式;另外,请注意,具有相同装饰器的属性组之间有一个空行 - 我认为这有助于提高可读性:

我对此没有强烈的意见,但尝试将未用任何装饰器标记的私有和公共组件属性与装饰属性分开定位。

根据我的经验,混淆它们只会导致混乱和混乱的感觉。

命名

哦,我知道,给事物命名很难。

在命名方面,我总是需要三思而后行,才能想出一个易于理解、明确且易于搜索的名称:

  • 可以理解:乍一看,这有什么作用?

  • 明确:例如,如果我们在一个组件上有多个点击事件,那么这个事件指的是哪一个?所以,将其命名为onClick显然是不合适的。

  • 易于搜索:我认为命名代码有点像 SEO:我的用户(队友或我)将如何搜索这个特定的东西 - 以及我该如何编写它以确保他们可以更轻松地搜索它?

文件名

我喜欢在所有文件名中使用连字符。我认为这现在应该是 Typescript 项目的标准,但我见过不少变体,甚至在 Angular 项目中也是如此,所以我觉得有必要提一下。

例子:

  • 注册.组件.ts

  • 个人资料表单.组件.html

路线组件

我倾向于用后缀 page 来命名路由组件。

例如,身份验证页面通常被称为 auth-page.component.ts - 这告诉我它是一个路由组件,我通常使用它通过路由器出口包装和显示其他组件。

成分

我在命名组件时倾向于遵循的一些规则是:

  • 尽量使用不超过3个单词(不包括前缀)。没什么特别的原因——只是它们看起来不太美观。当然,有时遵守这条规则并不容易。

  • 尽量避免重复已经在其他组件中使用过的单词或上下文,因为这会减慢使用 IDE 搜索功能的速度,还会导致错误地打开其他文件,最终浪费时间和造成挫败感

  • 同时,也尽量不要太笼统。例如:如果我们将一个组件称为“设置”——那是什么设置!?在这里帮忙提供一些上下文信息(例如:应用程序设置、配置文件设置、组织设置等等)。
    对于小型应用程序来说这没什么大不了的,但规模化应用就不一样了。

事件名称

它看起来很简单但实际上却不然,特别是对于具有许多事件的较大组件而言。

以下是我尝试遵循的一组规则:

  • 不要在事件/输出名称前添加 on 前缀。处理程序可以改为使用这样的前缀

  • 别让我思考:务必指定操作所引用的实体,而不仅仅是操作本身。
    如果我们要描述组件上值发生变化的事件,则事件变化可以是 valueChange。
    在我看来,这很明确,并且告诉我发生了什么变化,而无需我质疑这是值、状态还是其他任何东西。

  • 是否使用过去式(valueChange 与 valueChanged)?这个问题存在争议,我听到过双方给出的合理理由,所以你和你的团队或许可以讨论一下。
    只要你们就其中一种方式达成一致,我觉得这并不重要。你觉得呢?

ES 进口

保持文件导入的有序和整洁是一项挑战,尤其是在使用 IDE 自动添加导入内容的情况下。随着文件的增长,它们往往会变得非常混乱。

这是我订购进口的方式:

  • Angular 导入总是放在顶部

  • 处方导入

  • 第三方(非核心)

  • 最后的本地/项目导入

在每个组上方留下评论也是一个好习惯:

要点⭐

  • 整齐地包装 HTML 元素:每行放置 1 个属性,并按类型对属性进行排序

  • 使用括号括起使用管道的值

  • 将生命周期钩子彼此相邻放置,并按执行顺序排列

  • 在命名事物时,问问自己:这是否可以理解、明确且易于搜索?

  • 保持 ES 导入整洁有序

固执己见的 Angular

我添加了一个名为Opinionated Angular的 Github 存储库,我将在其中倾注更多想法来编写可读且美观的 Angular 代码。

如果您愿意的话,请过来贡献!

我很乐意收到一些建议,并了解您和您的团队遵循的惯例和规则。或者,如果您需要任何澄清,或者您认为某些内容不清楚或有错误,请留言!

希望你喜欢这篇文章!如果喜欢,请在MediumTwitterDev上关注我,获取更多关于软件开发、前端、RxJS、Typescript 等的文章!

文章来源:https://dev.to/angular/an-opinionated-coding-styleguide-for-angular-k60
PREV
让我们实现一个像 Angular Material Site 一样的主题切换🎨欢迎来到 Dev.to nanba!
NEXT
Angular 表单和指令的一个小技巧