随着Angular框架的不断发展,为了利用最新的功能和性能改进,升级到最新版本是每个开发者都需要面对的任务。本文将指导如何将Angular 8或9项目升级到Angular 10。
在开始升级到Angular 10之前,首先需要确保项目已经更新到Angular 9的最新补丁版本。此外,还需要对代码进行一些必要的修改,以确保兼容性。
如果已经有一个Angular 9项目,并且希望升级到Angular 10,那么以下是需要遵循的步骤:
在将项目升级到Angular 10之前,请确保首先更新到Angular 9的最新稳定版本。在终端中运行以下命令:
$ ng update @angular/core@9 @angular/cli@9
确保添加了Angular 9的版本号,以安装这个版本的最新补丁,否则可能会安装Angular 10。
如果已经将项目更新到Angular 9版本,只需要做几件事情:
TestBed.inject<T>
方法,而不是TestBed.get()
方法。@NgModule()
装饰器中移除entryComponents
属性,因为它们不再需要。如果已经对代码进行了必要的修改,并且将Angular项目更新到了Angular 9的最新补丁版本,那么可以使用ng update
命令将其更新到Angular 10。返回到终端并运行以下命令:
$ ng update @angular/cli @angular/core
注意:由于Angular 10不是当前的最终版本,需要使用--next
标志,如下所示:
$ ng update @angular/cli @angular/core --next
在升级过程中,可能需要对代码进行一些修改以确保兼容性。以下是一些常见的修改点:
如果在模板中使用了Angular表单的<ngForm>
指令,需要将任何<ngForm>
实例更新为<ng-form>
。例如,如果声明了一个如下的表单:
<ngForm #exampleForm="ngForm">
<input [(ngModel)]="userName" name="userName" />
</ngForm>
只需要按照以下方式更新:
<ng-form #exampleForm="ngForm">
<input [(ngModel)]="userName" name="userName" />
</ng-form>
使用的@ContentChild
和@ContentChildren
装饰器将不再能够匹配它们自己的宿主节点。
在Angular 9之前,可以这样使用@ContentChild
内容查询来访问指令的宿主ElementRef
:
@Directive({
selector: '[myActions]'
})
export class MyDirective implements AfterContentInit {
@ContentChild(MyDirective, {static: true, read: ElementRef})
selfElementRef: ElementRef;
constructor(private readonly renderer: Renderer2) {}
ngAfterContentInit() {
const el = this.selfElementRef.nativeElement as HTMLElement;
if (!el) {
return;
}
this.renderer.setStyle(el, 'color', 'black');
}
}
需要将之前的代码更改为通过注入依赖来访问ElementRef
:
@Directive({
selector: '[myActions]'
})
export class MyDirective implements AfterContentInit {
constructor(private readonly elementRef: ElementRef, private readonly renderer: Renderer2) {}
ngAfterContentInit() {
const el = this.elementRef.nativeElement as HTMLElement;
if (!el) {
return;
}
this.renderer.setStyle(el, 'color', 'black');
}
}
这样,就不需要使用@ContentChild()
和@ContentChildren()
装饰器来查询宿主元素了。
由于Angular 9+默认使用的Ivy渲染器,模板具有类型检查。在Angular 9版本之前,模板变量具有TypeScript的any
类型,即可以更改对象并使用未知属性,编译器不会报错。
从使用Ivy渲染器的Angular 9版本开始,模板变量将根据TypeScript编译器选项对模板类型检查的严格程度进行强类型化。因此,需要避免直接在模板中更改模板变量。
让看一个会改变模板变量的例子:
<button #myBtn (click)="myBtn.state = 'clicked'">
Click Me
</button>
在Angular 8版本中,myBtn
模板变量具有any
类型。从Angular 9版本开始,模板变量将具有内置的HTMLButtonElement
类型。因此,将会遇到错误,因为HTMLButtonElement
接口没有state
成员。
要修复这个问题,需要重构任何对模板变量的更改,并用组件方法替换它们。例如:
<button (click)="onClick()">
Click Me
</button>
简单地移除了模板变量,并在组件的类中添加了onClick()
方法和state
属性:
export class MyComponent {
state = 'not clicked';
onClick(): void {
this.state = 'clicked';
}
}