Angular 2 Component Inheritance
Angular 2.3 版本中引入了组件继承的功能,该功能非常强大,能够大大增加我们组件的可复用性。 Component Inheritance组件继承涉及以下的内容:
需要注意的是,模板是不能被继承的 ,因此共享的 DOM 结构或行为需要单独处理。了解详细信息,请查看 - properly support inheritance。 接下来我们来快速体验的组件继承的功能并验证以上的结论,具体示例如下(本文所有示例基于的 Angular 版本是 - 4.0.1): exe-base.component.ts import { Component,ElementRef,Input,HostBinding,HostListener,OnInit } from '@angular/core'; @Component({ selector: 'exe-base',// template will not be inherited template: ` <div> exe-base:我是base组件么? - {{isBase}} </div> ` }) export class BaseComponent implements OnInit { @Input() isBase: boolean = true; @HostBinding('style.color') color = 'blue'; // will be inherited @HostListener('click',['$event']) // will be inherited onClick(event: Event) { console.log(`I am BaseComponent`); } constructor(protected eleRef: ElementRef) { } ngOnInit() { console.dir('BaseComponent:ngOnInit method has been called'); } } exe-inherited.component.ts import { Component,OnChanges,SimpleChanges } from '@angular/core'; import { BaseComponent } from './exe-base.component'; @Component({ selector: 'exe-inherited',template: ` <div> exe-inherited:我是base组件么? - {{isBase}} </div> ` }) export class InheritedComponent extends BaseComponent implements OnChanges { @HostListener('click',['$event']) // overridden onClick(event: Event) { console.log(`I am InheritedComponent`); } ngOnChanges(changes: SimpleChanges) { console.dir(this.eleRef); // this.eleRef.nativeElement:exe-inherited } } app.component.ts import { Component,OnInit } from '@angular/core'; import {ManagerService} from "./manager.service"; @Component({ selector: 'exe-app',template: ` <exe-base></exe-base> <hr/> <exe-inherited [isBase]="false"></exe-inherited> ` }) export class AppComponent { currentPage: number = 1; totalPage: number = 5; }
(备注:BaseComponent 中 ngOnInit() 钩子被调用了两次哦) 接下来我们简要讨论一个可能令人困惑的主题, Component Inheritance In Action现在我们先来实现一个简单的分页组件,预期的效果如下:
(图片来源 - https://scotch.io/tutorials/c... 具体实现代码如下: simple-pagination.component.ts import { Component,Output,EventEmitter } from '@angular/core'; @Component({ selector: 'simple-pagination',template: ` <button (click)="previousPage()" [disabled]="!hasPrevious()">Previous</button> <button (click)="nextPage()" [disabled]="!hasNext()">Next</button> <p>page {{ page }} of {{ pageCount }} </p> ` }) export class SimplePaginationComponent { @Input() pageCount: number; @Input() page: number; @Output() pageChanged = new EventEmitter<number>(); nextPage() { this.pageChanged.emit(++this.page); } previousPage() { this.pageChanged.emit(--this.page); } hasPrevious(): boolean { return this.page > 1; } hasNext(): boolean { return this.page < this.pageCount; } } app.component.ts import { Component,template: ` <simple-pagination [page]="currentPage" [pageCount]="totalPage"></simple-pagination> ` }) export class AppComponent { currentPage: number = 2; totalPage: number = 10; } 假设我们现在想更换分页组件的风格,如下图所示:
(图片来源 - https://scotch.io/tutorials/c... 我们发现 UI 界面风格已经完全不一样了,但仔细想一下组件分页的控制逻辑仍可以继续使用。Angular 团队也考虑到了这种场景,因此为我们引入组件继承的特性,这对我们开发者来说,可以大大地提高组件的复用性。接下来我们来一步步实现新的分页组件,首先先更新 UI 界面,具体代码如下: exe-pagination.component.ts import { Component } from '@angular/core'; import { SimplePaginationComponent } from './simple-pagination.component'; @Component({ selector: 'exe-pagination',template: ` <a (click)="previousPage()" [class.disabled]="!hasPrevious()" href="javascript:void(0)"> ?? </a> <span>{{ page }} / {{ pageCount }}</span> <a (click)="nextPage()" [class.disabled]="!hasNext()" href="javascript:void(0)" > ?? </a> ` }) export class ExePaginationComponent extends SimplePaginationComponent { } 上面代码中,有几个注意点:
再继续开发 @Component({ selector: 'simple-pagination',template: ` <button (click)="previousPage()" [disabled]="!hasPrevious()">{{ previousText }}</button> <button (click)="nextPage()" [disabled]="!hasNext()">{{ nextText }}</button> <p>page {{ page }} of {{ pageCount }}</p> ` }) export class SimplePaginationComponent { ... @Input() previousText = 'Previous'; @Input() nextText = 'Next'; ... } 注意:
对于 import { Component,Output} from '@angular/core'; import { SimplePaginationComponent } from './simple-pagination.component'; @Component({ selector: 'exe-pagination',template: ` <a (click)="previousPage()" [class.disabled]="!hasPrevious()" href="javascript:void(0)"> ?? </a> <span>{{ page }} / {{ pageCount }}</span> <a (click)="nextPage()" [class.disabled]="!hasNext()" href="javascript:void(0)" > ?? </a> ` }) export class ExePaginationComponent extends SimplePaginationComponent { @Input() previousText = '<<'; // override default text @Input() nextText = '>>'; // override default text } 以上代码成功运行后,浏览器的输出结果如下:
功能已经实现了,但有时候我们想在分页中显示一个标题,且支持用户自定义该标题,那就得在现有组件的基础上,再新增一个 import { Component,template: ` <h2>{{ title }}</h2> <a (click)="previousPage()" [class.disabled]="!hasPrevious()" href="javascript:void(0)"> ?? </a> <span>{{ page }} / {{ pageCount }}</span> <a (click)="nextPage()" [class.disabled]="!hasNext()" href="javascript:void(0)" > ?? </a> ` }) export class ExePaginationComponent extends SimplePaginationComponent { @Input() previousText = '<<'; // override default text @Input() nextText = '>>'; // override default text @Input() title: string; // title input for child component only } 我有话说1.面向对象编程中类的概念?传统的 JavaScript 程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 从 ECMAScript 2015,也就是ECMAScript 6 开始,JavaScript 程序员将能够使用基于类的面向对象的方式。 使用 TypeScript,我们允许开发者现在就使用这些特性,并且编译后的 JavaScript 可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript 版本。 类的概念虽然 JavaScript 中有类的概念,但是可能大多数 JavaScript 程序员并不是非常熟悉类,这里对类相关的概念做一个简单的介绍。
TypeScript 类示例class Greeter { private greeting: string; // 定义私有属性,访问修饰符:public、protected、private constructor(message: string) { // 构造函数,一般执行用于进行数据初始化操作 this.greeting = message; } greet() { // 定义方法 return "Hello," + this.greeting; } } let greeter = new Greeter("world"); 2.面向对象编程中继承的概念是什么?
继承 (Inheritance) 是一种联结类与类的层次模型。指的是一个类 (称为子类、子接口) 继承另外的一个类 (称为父类、父接口) 的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;继承是一种 is-a 关系。
(图片来源网络) TypeScript 类继承示例class Animal { name:string; constructor(theName: string) { this.name = theName; } move(distanceInMeters: number = 0) { console.log(`${this.name} moved ${distanceInMeters}m.`); } } class Snake extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 5) { console.log("Slithering..."); super.move(distanceInMeters); } } let sam = new Snake("Sammy the Python"); sam.move(); 参考资源
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |