简介
如果您在ANGLE上花过任何时间,那么您可能遇到过想要共享数据或功能而使用services/providers.的情况
如果您想要的不是通用数据功能,而是通用用户界面功能,该怎么办?例如,考虑一个简单的场景,其中您希望使用按钮从一个组件导航到另一个组件。实现这一点的一种简单方法是创建一个按钮,在代码中调用一个方法,然后使用角度路由器导航到页面。如果您不想在每个组件中重复相同的代码,该怎么办?类型脚本和角度为您提供了一种处理这种封装的方法。继承的组件!
使用TypeScrip中的类继承,您可以声明一个包含通用UI功能的基本组件,并使用它来扩展您想要的任何标准组件。如果您习惯于任何侧重于面向对象方法的语言,如C# ,您会很容易地将这种方法识别为继承。对于TypeScrip,它仅仅被称为扩展类。
在本文中,您将把常用代码封装在一个基本组件中,并对其进行扩展以创建可重用的页面导航按钮。
前提条件
要完成本教程,您需要:
- 本地安装node.js,可按照如何安装node.js并创建本地开发Environment.
- 对设置角度project.》有所了解
本教程已使用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
这些命令将生成一个PageoneComponent
、PagetwoComponent
和PagethreeComponent
,并将这三个添加为app
的delcarations
。
打开我们第一次生成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
点击其中一个按钮,并观察您是否被定向到预期页面。
封装单个组件的功能需要大量开销,因此让我们同时扩展Pagetwo
和Pagethree
组件,并添加按钮以帮助导航到其他页面。
首先,打开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
,为pageone
和pagethree
添加一个按钮:
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
,为pageone
和pagetwo
添加一个按钮:
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.上找到