容器与表示组件

的基本概念之一Angular应用中的组件架构是在容器和表示组件之间找到正确的平衡。

让我们来定义它们是什么:

  • 表示组件都是可重用的简单UI。比如按钮、对话框、卡片、导航栏等。
  • 容器组件恰恰相反:它们不可重复使用。它们被绑定到一个特定的用例。这些通常是整个屏幕或子屏幕,应用组件等。

从代码的角度来看,容器组件使用服务与后端交互。这样的组件知道使用这些服务从哪里获取数据,然后使用输入将数据提供给它们的子组件,这些子组件是表示组件:

识别这些组件的一个简单方法是演讲组件只有输入和输出,没有依赖注入。容器组件具有依赖注入而且很可能没有输入和输出。

什么时候使用容器组件和表示组件?

假设您的组件很适合成为表示组件,但正在使用服务。在这种情况下,您很可能将该服务注入到它的父容器中,然后使用输入将数据传递给该组件。这样,您的表示组件就可以在其他地方重用,而不必绑定到特定的用例。

当然,就像任何最佳实践一样,也有例外情况需要考虑。有些时候可重用性是有意义的,而有些时候则不然。如果没有意义,不要强迫你的组件归入这些类别,但如果能快速取得成功,可以尝试一下。您的应用程序体系结构(可能还有性能——请继续关注这方面的更多内容)以后会感谢您的。

如何更新我的Angular版本?

昨天,我们提到了为什么它是必要的让你的Angular版本尽可能保持最新

今天,我们来看看如何做到这一点。一个简明的答案是使用的说明https://update.angular.io因为所有的信息都在那里。您可以选择当前版本,即您想要升级到的版本,单击按钮,然后您将获得详细的TODO列表:

典型的升级包括:

  1. 升级当前版本的Angular CLI:安装-g @angular/cli@latest
  2. 将项目代码升级到最新版本:Ng更新@angular/core@latest @angular/cli@latest

ng更新命令会更新Angular和它的依赖项,如果框架的新版本有一些破坏性的变化(意味着一些函数或类被重命名或替换为其他东西),甚至会改变你的代码。是的,都是自动的!

在某些情况下,升级可能会更加困难:

  1. 例如,如果你有不再维护的依赖项,或者在几周/几个月后才升级-我会在本通讯的后续版本中解决这个问题。
  2. 如果Angular需要升级Node.js,这意味着升级你的开发环境和持续集成服务器。

同样,关键是要尽可能保持最新,每六个月升级一次5到10分钟的任务,而不是每隔几年就花2周的时间。

Angular发布时间表

Angular在不断发展。快速浏览一下框架的发布说明,就会发现每周都有新的发布。例如,昨天,我们提到了最新的Angular 15.1的更新

让我们来讨论一下Angular的发布频率。主要发布节奏如下:

  • 主要版本每六个月发布一次(Angular 16在Angular 15发布六个月后发布)
  • 如果需要的话,每个月发布一个次要版本,通常每个主要版本之间会有1到3个版本(Angular 15.2在15.1后一个月发布)
  • 如果需要,每周更新版本(Angular 15.1.1在15.1.0之后的一周发布)

这很重要,因为你可以做到计划升级基于这种节奏。例如,我的一些咨询客户计划他们的应用程序的主要发布一年两次,在他们获得一个新版本的Angular后一个月。

知道这一点也很重要主要版本支持18个月.这只适用于关键修复和安全补丁。新特性和改进被添加到一个主要版本六个月寿命

到今天为止,这里是积极支持的版本:

如果您使用的是13年以上的任何版本,那么您就脱离了支持窗口,并可能面临bug、漏洞和其他问题。因此,总是建议尽可能多地使用最新的主版本,或者作为B计划,保留一个或两个主版本,而不是更多。

你可以在这里阅读这种方法背后的全部原理,以及更多关于Angular发布计划的信息:https://angular.io/guide/releases

ngrxLet:异步管道的更好版本

昨天,我们提到如何异步管材可配合使用* ngIf* ngFor在我们的模板中声明一个局部变量,允许我们使用相同的数据有多个表达式:

              
              
<<跨度class="hljs-name">div*<跨度class="hljs-attr">ngIf=<跨度class="hljs-string">"user$ | async as user"><跨度class="hljs-tag"><<跨度class="hljs-name">p>名字:{{用户。firstName}}<跨度class="hljs-tag">p><跨度class="hljs-tag"><<跨度class="hljs-name">p>姓:{{用户。lastName}}<跨度class="hljs-tag">p><跨度class="hljs-tag">div>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

虽然上面的代码运行得很好,但添加其他代码并不总是很方便* ngIf* ngFor在我们的模板中。异步管道的另一个缺点是它不让我们知道是否可观测的发生错误或成功完成。

这就是ngrxLet指令可以解决问题,因为它用简单的语法解决了上述所有缺点。我们之前的例子变成:

              
<<跨度class="hljs-name">div*<跨度class="hljs-attr">ngrxLet=<跨度class="hljs-string">"user$ as user"><跨度class="hljs-tag"><<跨度class="hljs-name">p>名字:{{用户。firstName}}<跨度class="hljs-tag">p><跨度class="hljs-tag"><<跨度class="hljs-name">p>姓:{{用户。lastName}}<跨度class="hljs-tag">p><跨度class="hljs-tag">div>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

如果我们想要获得任何错误或可观察对象的完成状态,我们可以通过暴露的更多局部变量来实现ngrxLet

              
<<跨度class="hljs-name">div*<跨度class="hljs-attr">ngrxLet=<跨度class="hljs-string">“user$ as user;误差为e;完整为c">
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

你可以找到完整的工作示例ngrxLet可以使用NPM作为依赖项安装(NPM install @ngrx/component),重要的是要注意它不是全部ngrx状态管理库,只是它的一个很小的子集,所以使用该指令不需要使用其他任何东西ngrx

如果你想深入了解,这里有一个稍微扩展版本的教程链接,其中有更多信息:ngrxLet -一个更好的异步管道版本

异步管道语法技巧

昨天,我们写过如何使用异步管道自动订阅和取消订阅从我们的观测数据。

当我教授这个话题时,人们通常至少有以下两种反对意见之一:

如果我还需要订阅的数据在我的Typescript代码?

首先,使用异步pipe似乎只允许您访问HTML模板中的数据。但事实并非如此,因为你仍然可以使用tap操作符来“监视”你的可观察对象,并从中获取数据。例如(完整例子):

              
.的名字$ = nameService.getName()。管(丝锥(<跨度class="hljs-function">的名字=><跨度class="hljs-keyword">这.的名字=的名字));
代码语言:<跨度class="shcb-language__name">打印稿<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">打印稿<跨度class="shcb-language__paren">)

然后在HTML模板中:

              
<<跨度class="hljs-name">p>异步管道的名称:{{Name $ | async}}<跨度class="hljs-tag">p>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

如果我需要从订阅中的对象中读取多个属性怎么办?

另一种说法是,你不想以这样的方式结束:

              
<<跨度class="hljs-name">p>名字:{{(用户$ | async)?。firstName}}<跨度class="hljs-tag">p><跨度class="hljs-tag"><<跨度class="hljs-name">p>姓氏:{{(用户$ | async)?。lastName}}<跨度class="hljs-tag">p>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

上面的代码很难阅读,每个属性都需要一个订阅。这本身就是一场灾难,因为每个订阅都可能触发来自服务器的相同数据的HTTP请求!

相反,您可以这样做,只使用一个订阅,将结果存储在一个局部变量中,然后在数据可用时呈现数据。此技术适用于任何结构指令,例如* ngIf* ngFor

              
<<跨度class="hljs-name">div*<跨度class="hljs-attr">ngIf=<跨度class="hljs-string">"user$ | async as user"><跨度class="hljs-tag"><<跨度class="hljs-name">p>名字:{{用户。firstName}}<跨度class="hljs-tag">p><跨度class="hljs-tag"><<跨度class="hljs-name">p>姓:{{用户。lastName}}<跨度class="hljs-tag">p><跨度class="hljs-tag">div>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

如果通过添加元素来适应订阅来更改DOM结构让您感到困扰,那么您可以使用ng-template相反,尽管这里的语法也可能有点令人不安:

              
<<跨度class="hljs-name">ng-template[<跨度class="hljs-attr">ngIf] =<跨度class="hljs-string">"user$ | async"<跨度class="hljs-attr">让用户><跨度class="hljs-tag"><<跨度class="hljs-name">p>名字:{{用户。firstName}}<跨度class="hljs-tag">p><跨度class="hljs-tag"><<跨度class="hljs-name">p>姓:{{用户。lastName}}<跨度class="hljs-tag">p><跨度class="hljs-tag">ng-template>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

好了,今天就到这里吧。明天,我们将看到我们如何做得比现在更好。

如何避免RxJs可观察对象的内存泄漏?

在大型Angular应用程序中,最容易陷入麻烦的方法是不取消订阅可观察对象会造成内存泄漏.虽然有不同的技术自动取消订阅可观察对象,一种方法更简洁、优雅,而且总体上是最防错的。

这个技巧就是使用异步从Angular框架。

为什么异步管这么厉害的工具?

  1. 首先,它自动订阅可观察对象,因此我们不再需要调用.subscribe ()
  2. 它返回来自该可观察对象的数据,在我们的组件需要显示最新数据时触发Angular的更改检测。
  3. 最后,当我们的组件被销毁时,它会自动从可观察对象中取消订阅。

所有这一切都只需要6个字符!(好吧,如果你想计算空白,可能会多一点):

              
<<跨度class="hljs-name">div>{{myObservable | async}}<跨度class="hljs-tag">div>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

异步如果我们不使用Pipe,它的工作方式与我们编写的代码完全相同(因此会反复重复,使代码库更大,从而使代码更慢)。

检查它的源代码在这里,您将看到它所做的一切都是实现ngOnDestroy取消订阅我们的可观察对象。

没有任何好的理由不使用异步管道,如果您认为您有一些理由,请继续关注我们的下一条消息,因为我们将介绍一些关于使用该管道的很好的提示和技巧。

如何为Angular应用程序生成文档?

编写软件文档是很困难的。不仅如此,维护软件文档更加复杂,而且常常被人遗忘。

那么,解决方案是什么呢?使用自动化的解决方案如何:

  1. 从代码注释生成文档,不需要Wiki或任何第三方软件。
  2. 自动生成上述文档,并且可以作为构建过程的一部分。
  3. 向开发人员提供指标和反馈,鼓励他们编写更多的文档。

这样的解决方案是存在的。它被称为Compodoc.Compodoc可以从应用程序中编写的所有注释中生成一个类似javadoc的网站(您可以看到这里是此类文档的示例):

Compodoc可以通过npm全局安装:

              
npm<跨度class="hljs-selector-tag">安装<跨度class="hljs-selector-tag">- g<跨度class="hljs-keyword">@compodoc/ compodoc
代码语言:<跨度class="shcb-language__name">CSS<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">css<跨度class="shcb-language__paren">)

或者你也可以在本地将它添加到单个Angular项目中ng添加项目文件夹中的原理图:

              
ng<跨度class="hljs-selector-tag">添加<跨度class="hljs-keyword">@compodoc/ compodoc
代码语言:<跨度class="shcb-language__name">CSS<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">css<跨度class="shcb-language__paren">)

然后你就可以创建一个配置文件来决定包含哪些文件(例如,你可能想要排除test,并且Compodoc已经准备好只用一个命令就可以运行:

              
npx<跨度class="hljs-selector-tag">compodoc<跨度class="hljs-selector-tag">- p<跨度class="hljs-selector-tag">tsconfig<跨度class="hljs-selector-class">. doc<跨度class="hljs-selector-class">. json
代码语言:<跨度class="shcb-language__name">CSS<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">css<跨度class="shcb-language__paren">)

上面的命令创建了一个静态HTML网站,记录了整个应用程序的所有模块/组件/管道/指令/服务。

我最喜欢的功能是文档覆盖统计使用一个类似于开发人员所熟悉的测试覆盖率报告的报告,显示应用程序的哪些部分是良好记录的,哪些部分不是。

Angular中的格式化函数

我们提到过的默认配置选项日期在Angular中。

你知道我们也可以在Typescript代码中使用日期格式吗formatDate函数?

此函数具有与日期管道相同的签名,这非常有意义,因为管道本身使用的函数(源代码在这里):

              
formatDate(值:字符串|数字| .<跨度class="hljs-built_in">日期,<跨度class="hljs-attr">格式:字符串,<跨度class="hljs-attr">语言环境:字符串,时区?:字符串):字符串
代码语言:<跨度class="shcb-language__name">JavaScript<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">javascript<跨度class="shcb-language__paren">)

使用该函数所需要的只是将其导入@angular /常见

              
进口{formatDate}<跨度class="hljs-keyword">从<跨度class="hljs-string">“@angular /普通”
代码语言:<跨度class="shcb-language__name">JavaScript<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">javascript<跨度class="shcb-language__paren">)

该函数的唯一缺点是没有默认格式或区域设置,因此必须将这两个值作为参数传递,而对于日期管道。

顺便说一下,类似的功能可用于数字、货币和百分比:

关于这些函数的更多信息,我有这个教程用Angular格式化日期和数字

日期管道默认格式和时区

日期管道是用Angular格式化日期的最方便的方法。然而,通常情况下,我们需要在整个应用程序中使用一致的日期格式,这意味着每次使用日期管道时都必须传递自定义格式:

              
<<跨度class="hljs-name">跨度>今天是{{今天|日期:'月/日/日'}}<跨度class="hljs-tag">跨度>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

当然,我们可以将该格式存储在一个常量中,并在每次使用管道时重用该常量,但这不是很方便。

幸运的是,从Angular 15开始,我们现在可以通过配置一个名为DATE_PIPE_DEFAULT_OPTIONS

它的工作原理是将以下代码添加到依赖注入配置(数组的供应商)app.modules.ts

              
提供者:[{<跨度class="hljs-attr">提供: DATE_PIPE_DEFAULT_OPTIONS,<跨度class="hljs-attr">useValue:{<跨度class="hljs-attr">dateFormat:<跨度class="hljs-string">“MM / dd / yy”}}]
代码语言:<跨度class="shcb-language__name">JavaScript<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">javascript<跨度class="shcb-language__paren">)

有了这样的配置,我们就可以在没有任何参数的情况下使用管道,并在整个应用程序中自动应用默认格式:

              
<<跨度class="hljs-name">跨度>今天是{{今天|日期}}<跨度class="hljs-tag">跨度>
代码语言:<跨度class="shcb-language__name">HTML、XML<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">xml<跨度class="shcb-language__paren">)

属性也可以自定义时区时区相同的属性DatePipeConfig对象。

调试器关键字

昨天,我们介绍了如何使用带有

标记的JSON管道在网页上调试JSON数据。

今天,我想介绍另一种可以节省时间的调试技术调试器关键字。

当你想在你的web应用程序中添加断点时,添加Javascript指令:

              
调试器
代码语言:<跨度class="shcb-language__name">JavaScript<跨度class="shcb-language__paren">(<跨度class="shcb-language__slug">javascript<跨度class="shcb-language__paren">)

然后在浏览器中打开开发工具并导航到应用程序URL。只要Javascript碰到调试器语句,运行时就会停止在那个断点上,允许你调试代码:

一旦浏览器在该断点上暂停,就可以通过单击浏览器开发工具中的行号添加其他断点,就像常规调试器一样。

有两件重要的事情需要注意:

  1. 断点仅在开发工具打开时才有效
  2. 别忘了去掉调试器语句。您可能不希望将其发布到生产环境中。