如何使用 Angular 组件继承扩展类

简介

如果您在ANGLE上花过任何时间,那么您可能遇到过想要共享数据或功能而使用services/providers.的情况

如果您想要的不是通用数据功能,而是通用用户界面功能,该怎么办?例如,考虑一个简单的场景,其中您希望使用按钮从一个组件导航到另一个组件。实现这一点的一种简单方法是创建一个按钮,在代码中调用一个方法,然后使用角度路由器导航到页面。如果您不想在每个组件中重复相同的代码,该怎么办?类型脚本和角度为您提供了一种处理这种封装的方法。继承的组件!

使用TypeScrip中的类继承,您可以声明一个包含通用UI功能的基本组件,并使用它来扩展您想要的任何标准组件。如果您习惯于任何侧重于面向对象方法的语言,如C# ,您会很容易地将这种方法识别为继承。对于TypeScrip,它仅仅被称为扩展类。

在本文中,您将把常用代码封装在一个基本组件中,并对其进行扩展以创建可重用的页面导航按钮。

前提条件

要完成本教程,您需要:

本教程已使用Node v16.4.2、npm v7.19.1和@angular/core v12.1.1进行了验证。

第一步-设置项目

让我们从使用Angel CLI创建一个新的应用程序开始。

如果你之前没有安装过Angular CLI,请使用npm全局安装:

1npm install -g @angular/cli

接下来,使用CLI创建新应用程序:

1ng new AngularComponentInheritance --style=css --routing --skip-tests

<$>[备注] 注意: 我们正在给ng new命令传递一些标志,以便在我们的APP中添加路由(--routing),而不添加任何测试文件(--Skip-tests)。 <$>

导航到项目目录:

1cd AngularComponentInheritance

然后,运行以下命令创建一个Base组件:

1ng generate component base --inline-template --inline-style --skip-tests --module app

<$>[备注] 注意: 这里的--mode标志指定组件应该属于哪个模块。 <$>

该命令将创建一个base.Component.ts文件,并将其添加为app模块的声明

第二步-构建基础组件

使用代码编辑器打开base/base.component.ts文件:

 1[label src/app/base/base.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3
 4@Component({
 5  selector: 'app-base',
 6  template: `
 7    <p>
 8      base works!
 9    </p>
10  `,
11  styles: [
12  ]
13})
14export class BaseComponent implements OnInit {
15
16  constructor() { }
17
18  ngOnInit(): void {
19  }
20
21}

这个用户界面永远不会显示,所以除了一个简单的用户界面外,不需要添加任何东西。

接下来,将Router注入组件:

 1[label src/app/base/base.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { Router } from '@angular/router';
 4
 5@Component({
 6  selector: 'app-base',
 7  template: `
 8    <p>
 9      base works!
10    </p>
11  `,
12  styles: [
13  ]
14})
15export class BaseComponent implements OnInit {
16
17  constructor(public router: Router) { }
18
19  ngOnInit(): void {
20  }
21
22}

注意可访问性级别。由于继承,将此声明公之于众很重要。

接下来,向基础组件添加一个名为openPage的方法,它接受一个字符串并使用它导航到路由(注意:使用下面的勾号而不是单引号模板文字):

 1[label src/app/base/base.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { Router } from '@angular/router';
 4
 5@Component({
 6  selector: 'app-base',
 7  template: `
 8    <p>
 9      base works!
10    </p>
11  `,
12  styles: [
13  ]
14})
15export class BaseComponent implements OnInit {
16
17  constructor(public router: Router) { }
18
19  ngOnInit(): void {
20  }
21
22  openPage(routename: string) {
23    this.router.navigateByUrl(`/${routename}`);
24  }
25}

这为我们提供了所需的基本功能,因此让我们在一些组件上使用它。

第三步-继承组件

我们将运行三个角度CLI命令以生成更多组件:

1ng generate component pageone --skip-tests --module app
2ng generate component pagetwo --skip-tests --module app
3ng generate component pagethree --skip-tests --module app

这些命令将生成一个PageoneComponentPagetwoComponentPagethreeComponent,并将这三个添加为appdelcarations

打开我们第一次生成APP时CLI创建的app-routing.mode.ts,为每个页面添加一条路径:

 1[label src/app/app-routing.module.ts]
 2import { NgModule } from '@angular/core';
 3import { RouterModule, Routes } from '@angular/router';
 4import { PageoneComponent } from './pageone/pageone.component';
 5import { PagetwoComponent } from './pagetwo/pagetwo.component';
 6import { PagethreeComponent } from './pagethree/pagethree.component';
 7
 8const routes: Routes = [
 9  { path: '', component: PageoneComponent },
10  { path: 'pageone', component: PageoneComponent },
11  { path: 'pagetwo', component: PagetwoComponent },
12  { path: 'pagethree', component: PagethreeComponent }
13];
14
15@NgModule({
16  imports: [RouterModule.forRoot(routes)],
17  exports: [RouterModule]
18})
19export class AppRoutingModule { }

打开页面组件,让它扩展``BaseComponent

 1[label src/app/pageone/pageone.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { BaseComponent } from '../base/base.component';
 4
 5@Component({
 6  selector: 'app-pageone',
 7  templateUrl: './pageone.component.html',
 8  styleUrls: ['./pageone.component.css']
 9})
10export class PageoneComponent extends BaseComponent implements OnInit {
11
12  constructor() { }
13
14  ngOnInit(): void {
15  }
16
17}

以及添加路由器并使用super将其注入到BaseComponent构造函数中:

 1[label src/app/pageone/pageone.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { Router } from '@angular/router';
 4import { BaseComponent } from '../base/base.component';
 5
 6@Component({
 7  selector: 'app-pageone',
 8  templateUrl: './pageone.component.html',
 9  styleUrls: ['./pageone.component.css']
10})
11export class PageoneComponent extends BaseComponent implements OnInit {
12
13  constructor(public router: Router) {
14    super(router);
15  }
16
17  ngOnInit(): void {
18  }
19
20}

这将获取注入的路由器模块,并将其传递到扩展组件。

接下来,对其余页面组件重复这些更改。

由于从基本组件传递的继承,在基本组件上定义的任何内容都可用于扩展它的所有组件。因此,让我们使用基本功能。

让我们在pageone.Component.html模板中添加两个按钮:

1[label src/app/pageone/pageone.component.html]
2<button type="button" (click)="openPage('pagetwo')">
3  Page Two
4</button>
5
6<button type="button" (click)="openPage('pagethree')">
7  Page Three
8</button>

注意到使用OpenPage方法不需要额外的限定吗?如果您考虑如何在像C# 这样的语言中进行类似的继承,您会调用类似于base.OpenPage()的代码。您不必使用TypeScrip执行此操作的原因是因为在转换过程中发生的魔力。TypeScrip将代码转换为JavaScript,并将base组件模块导入到pageone组件中,这样组件就可以直接使用它。

查看编译后的JavaScript可以更清楚地看到:

 1var PageoneComponent = /** @class */ (function (_super) {
 2    __extends(PageoneComponent, _super);
 3    function PageoneComponent(router) {
 4        var _this = _super.call(this, router) || this;
 5        _this.router = router;
 6        return _this;
 7    }
 8    PageoneComponent.prototype.ngOnInit = function () {
 9    };
10    PageoneComponent = __decorate([
11        Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({
12            selector: 'app-pageone',
13            template:
14             __webpack_require__("./src/app/pageone/pageone.component.html"),
15            styles: [
16              __webpack_require__("./src/app/pageone/pageone.component.css")
17            ]
18        }),
19        __metadata("design:paramtypes",
20            [_angular_router__WEBPACK_IMPORTED_MODULE_2__["Router"]])
21    ], PageoneComponent);
22    return PageoneComponent;
23}(_base_base_component__WEBPACK_IMPORTED_MODULE_1__["BaseComponent"]));

这也是我们需要将注入的模块保持为)base组件的构造函数的调用方式,需要传递所有注入的模块。当模块是Private‘时,它们将成为单独的声明。保持它们的‘Public’,并使用Super传递它们,它们仍然是一个单一的声明。

第四步-完成App

花点时间使用代码编辑器从app.component.html中删除样板代码,只留下<router-outlet>

1[label src/app/app.component.html]
2<router-outlet></router-outlet>

Pageone完成后,让我们使用CLI运行该应用程序,并研究其功能:

1ng serve

点击其中一个按钮,并观察您是否被定向到预期页面。

封装单个组件的功能需要大量开销,因此让我们同时扩展PagetwoPagethree组件,并添加按钮以帮助导航到其他页面。

首先,打开pagetwo.Component.ts,更新为pageone.Component.ts

 1[label src/app/pagetwo/pagetwo.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { Router } from '@angular/router';
 4import { BaseComponent } from '../base/base.component';
 5
 6@Component({
 7  selector: 'app-pagetwo',
 8  templateUrl: './pagetwo.component.html',
 9  styleUrls: ['./pagetwo.component.css']
10})
11export class PagetwoComponent extends BaseComponent implements OnInit {
12
13  constructor(public router: Router) {
14    super(router);
15  }
16
17  ngOnInit(): void {
18  }
19
20}

然后打开pagetwo.Component.html,为pageonepagethree添加一个按钮:

1[label src/app/pagetwo/pagetwo.component.html]
2<button type="button" (click)="openPage('pageone')">
3  Page One
4</button>
5
6<button type="button" (click)="openPage('pagethree')">
7  Page Three
8</button>

接下来,打开pagethree.Component.ts,更新为pageone.Component.ts

 1[label src/app/pagethree/pagethree.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { Router } from '@angular/router';
 4import { BaseComponent } from '../base/base.component';
 5
 6@Component({
 7  selector: 'app-pagethree',
 8  templateUrl: './pagethree.component.html',
 9  styleUrls: ['./pagethree.component.css']
10})
11export class PagethreeComponent extends BaseComponent implements OnInit {
12
13  constructor(public router: Router) {
14    super(router);
15  }
16
17  ngOnInit(): void {
18  }
19
20}

然后打开pagethree.Component.html,为pageonepagetwo添加一个按钮:

1[label src/app/pagethree/pagethree.component.html]
2<button type="button" (click)="openPage('pageone')">
3  Page One
4</button>
5
6<button type="button" (click)="openPage('pagetwo')">
7  Page Two
8</button>

现在,你可以在应用程序中导航,而不需要重复任何逻辑。

结论

在本文中,您将常用代码封装在一个基本组件中,并对其进行扩展以创建可重用的页面导航按钮。

从这里可以很容易地看到如何跨多个组件扩展通用功能。无论您是在处理导航、公共模式警报用户界面还是其他任何东西,使用通过类型脚本授予的继承模型来扩展组件都是一个强大的工具,可以保留在我们的工具箱中。

本教程的代码可在GitHub.上找到

Published At
Categories with 技术
Tagged with
comments powered by Disqus