Làm thế nào để mở rộng / kế thừa các thành phần?


159

Tôi muốn tạo các phần mở rộng cho một số thành phần đã được triển khai trong Angular 2, mà không phải viết lại chúng gần như hoàn toàn, vì thành phần cơ sở có thể trải qua các thay đổi và mong muốn những thay đổi này cũng được phản ánh trong các thành phần dẫn xuất của nó.

Tôi đã tạo ra ví dụ đơn giản này để cố gắng giải thích rõ hơn các câu hỏi của mình:

Với thành phần cơ bản sau app/base-panel.component.ts:

import {Component, Input} from 'angular2/core';

@Component({
    selector: 'base-panel',
    template: '<div class="panel" [style.background-color]="color" (click)="onClick($event)">{{content}}</div>',
    styles: [`
    .panel{
    padding: 50px;
  }
  `]
})
export class BasePanelComponent { 

  @Input() content: string;

  color: string = "red";

  onClick(event){
    console.log("Click color: " + this.color);
  }
}

Bạn có muốn tạo một thành phần phái sinh khác chỉ thay đổi, ví dụ, một hành vi thành phần cơ bản trong trường hợp màu ví dụ app/my-panel.component.ts:

import {Component} from 'angular2/core';
import {BasePanelComponent} from './base-panel.component'

@Component({
    selector: 'my-panel',
    template: '<div class="panel" [style.background-color]="color" (click)="onClick($event)">{{content}}</div>',
    styles: [`
    .panel{
    padding: 50px;
  }
  `]
})
export class MyPanelComponent extends BasePanelComponent{

  constructor() {
    super();
    this.color = "blue";
  }
}

Hoàn thành ví dụ làm việc trong Plunker

Lưu ý: Rõ ràng ví dụ này là đơn giản và có thể được giải quyết nếu không không cần sử dụng tính kế thừa, nhưng nó chỉ nhằm mục đích minh họa vấn đề thực sự.

Như bạn có thể thấy trong quá trình thực hiện thành phần phái sinh app/my-panel.component.ts, phần lớn việc thực hiện đã được lặp lại và phần duy nhất thực sự được kế thừa là class BasePanelComponent, nhưng @Componentvề cơ bản phải được lặp lại hoàn toàn, không chỉ là các phần thay đổi, như selector: 'my-panel'.

Có cách nào để tạo một sự kế thừa đầy đủ theo nghĩa đen của một thành phần Angular2, kế thừa classđịnh nghĩa của các đánh dấu / chú thích, chẳng hạn @Component?

Chỉnh sửa 1 - Yêu cầu tính năng

Yêu cầu tính năng angular2 được thêm vào dự án trên GitHub: Mở rộng / Kế thừa các chú thích thành phần angular2 # 7968

Chỉnh sửa 2 - Yêu cầu đã đóng

Yêu cầu đã bị đóng, vì lý do này , một thời gian ngắn sẽ không biết làm thế nào để hợp nhất trang trí sẽ được thực hiện. Để lại cho chúng tôi không có lựa chọn. Vì vậy, ý kiến ​​của tôi được trích dẫn trong Vấn đề .


Kiểm tra câu trả lời này stackoverflow.com/questions/36063627/ Trân trọng
NicolasB

Ok NicolasB. Nhưng vấn đề của tôi là với sự kế thừa của trình trang trí @Component, không được áp dụng cho siêu dữ liệu thừa kế. = /
Fernando Leal

người, xin vui lòng tránh sử dụng thừa kế với góc cạnh. ví dụ: lớp xuất khẩu PlnedFilterComponent mở rộng Tóm tắtFilterComponent thực hiện OnInit {là rất xấu. Có nhiều cách khác để chia sẻ mã, ví dụ như dịch vụ và các thành phần nhỏ hơn. Kế thừa không phải là cách góc cạnh. Tôi đang ở trong một dự án góc cạnh nơi họ đã sử dụng tính kế thừa và có những thứ phá vỡ như xuất các thành phần kế thừa từ các thành phần trừu tượng thiếu đầu vào của lớp trừu tượng.
vua robert

1
thay vào đó, hãy sử dụng phép chiếu nội dung, ví dụ như github.com/angular/components/blob/master/src/m vật liệu / thẻ / không sử dụng quyền thừa kế
vua robert

Câu trả lời:


39

Giải pháp thay thế:

Câu trả lời này của Thierry Templier là một cách khác để giải quyết vấn đề.

Sau một số câu hỏi với Thierry Templier, tôi đã đến ví dụ làm việc sau đây đáp ứng mong đợi của tôi như là một thay thế cho giới hạn thừa kế được đề cập trong câu hỏi này:

1 - Tạo trang trí tùy chỉnh:

export function CustomComponent(annotation: any) {
  return function (target: Function) {
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);

    var parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key => {
      if (isPresent(parentAnnotation[key])) {
        // verify is annotation typeof function
        if(typeof annotation[key] === 'function'){
          annotation[key] = annotation[key].call(this, parentAnnotation[key]);
        }else if(
        // force override in annotation base
        !isPresent(annotation[key])
        ){
          annotation[key] = parentAnnotation[key];
        }
      }
    });

    var metadata = new Component(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
  }
}

2 - Thành phần cơ sở với trang trí @Component:

@Component({
  // create seletor base for test override property
  selector: 'master',
  template: `
    <div>Test</div>
  `
})
export class AbstractComponent {

}

3 - Thành phần phụ với trang trí @CustomComponent:

@CustomComponent({
  // override property annotation
  //selector: 'sub',
  selector: (parentSelector) => { return parentSelector + 'sub'}
})
export class SubComponent extends AbstractComponent {
  constructor() {
  }
}

Plunkr với ví dụ đầy đủ.


3
Tôi giả sử rằng điều này sẽ không tương thích với trình biên dịch mẫu ngoại tuyến.
Günter Zöchbauer

@ GünterZöchbauer, tôi không có kiến ​​thức về "mẫu trình biên dịch ngoại tuyến" của Angular2. Nhưng tôi nghĩ rằng nó có thể không tương thích, và nó sẽ là một lựa chọn thay thế. Trường hợp chế độ "trình biên dịch mẫu ngoại tuyến" của Angular2 sẽ hữu ích? Bạn có thể chỉ cho tôi một cái gì đó để hiểu rõ hơn về điều này? Vì vậy, tôi có thể hiểu tầm quan trọng của khả năng tương thích này cho dự án của tôi.
Fernando Leal

Trình biên dịch mẫu ngoại tuyến (OTC) chưa hoạt động mặc dù nó đã được bao gồm trong RC.3. OTC sẽ phân tích các trình trang trí và tạo mã trong bước xây dựng khi có thể triển khai được. OTC cho phép loại bỏ trình phân tích và trình biên dịch Angular2 xử lý các trình trang trí và liên kết trong thời gian chạy, dẫn đến kích thước mã nhỏ hơn đáng chú ý và khởi tạo ứng dụng và thành phần nhanh hơn. OTC có thể sẽ trở nên có thể sử dụng được với một trong những cập nhật tiếp theo.
Günter Zöchbauer

1
@ GünterZöchbauer, bây giờ tôi hiểu tầm quan trọng của việc duy trì chức năng tương thích với OTC. Nó sẽ là một bản tổng hợp trước của các nhà trang trí góc cạnh giảm chi phí để khởi tạo các thành phần. Tôi muốn biết về chức năng của quy trình này và vì giải pháp của câu trả lời này sẽ không tương thích với OTC? Làm thế nào là biên soạn trước của trang trí? Có kiến ​​thức này, chúng tôi có thể nghĩ ra một cái gì đó để giữ chức năng thay thế này cho OTC. Cảm ơn bạn đã làm rõ!
Fernando Leal

24

Angular 2 phiên bản 2.3 vừa được phát hành, và nó bao gồm sự kế thừa thành phần gốc. Có vẻ như bạn có thể kế thừa và ghi đè bất cứ điều gì bạn muốn, ngoại trừ các mẫu và kiểu. Một số tài liệu tham khảo:


Một "gotcha" ở đây xảy ra khi bạn quên chỉ định một "bộ chọn" mới trong thành phần con. Bạn sẽ gặp lỗi thời gian chạy dọc theo dòng More than one component matched on this elementnếu không.
Aelfinn

@TheAelfinn Yeah: mỗi thành phần phải có một thông số đầy đủ trong @Component()thẻ. Nhưng, bạn có thể chia sẻ .html hoặc .css bằng cách tham khảo cùng một tệp nếu bạn muốn. Nói chung, đó là một điểm cộng lớn .
Daniel Griscom

Trong liên kết thứ hai của bạn scotch.io/tutorials/component-inherribution-in-angular-2 , tác giả tuyên bố rằng các thành phần kế thừa các dịch vụ phụ thuộc của cha mẹ chúng, mã của tôi đề nghị khác. Bạn có thể xác nhận rằng điều này được hỗ trợ?
Aelfinn

18

Bây giờ TypeScript 2.2 hỗ trợ Mixins thông qua các biểu thức Class, chúng ta có cách tốt hơn để thể hiện Mixins trên các Thành phần. Xin lưu ý rằng bạn cũng có thể sử dụng kế thừa Thành phần kể từ góc 2.3 ( thảo luận ) hoặc trang trí tùy chỉnh như được thảo luận trong các câu trả lời khác ở đây. Tuy nhiên, tôi nghĩ Mixins có một số thuộc tính khiến chúng thích hợp hơn cho việc sử dụng lại hành vi giữa các thành phần:

  • Mixins kết hợp linh hoạt hơn, tức là bạn có thể trộn và kết hợp Mixins trên các thành phần hiện có hoặc kết hợp Mixins để tạo thành Thành phần mới
  • Thành phần Mixin vẫn dễ hiểu nhờ sự tuyến tính hóa rõ ràng của nó đối với hệ thống phân cấp kế thừa lớp
  • Bạn có thể dễ dàng tránh các vấn đề với trang trí và chú thích gây ra sự kế thừa thành phần ( thảo luận )

Tôi thực sự khuyên bạn nên đọc thông báo TypeScript 2.2 ở trên để hiểu cách Mixins hoạt động. Các cuộc thảo luận được liên kết trong các vấn đề GitHub góc cạnh cung cấp thêm chi tiết.

Bạn sẽ cần những loại này:

export type Constructor<T> = new (...args: any[]) => T;

export class MixinRoot {
}

Và sau đó, bạn có thể khai báo một Mixin như Destroyablemixin này để giúp các thành phần theo dõi các đăng ký cần được xử lý trong ngOnDestroy:

export function Destroyable<T extends Constructor<{}>>(Base: T) {
  return class Mixin extends Base implements OnDestroy {
    private readonly subscriptions: Subscription[] = [];

    protected registerSubscription(sub: Subscription) {
      this.subscriptions.push(sub);
    }

    public ngOnDestroy() {
      this.subscriptions.forEach(x => x.unsubscribe());
      this.subscriptions.length = 0; // release memory
    }
  };
}

Để trộn Destroyablevào một Component, bạn khai báo thành phần của bạn như thế này:

export class DashboardComponent extends Destroyable(MixinRoot) 
    implements OnInit, OnDestroy { ... }

Lưu ý rằng MixinRootchỉ cần thiết khi bạn muốn extendmột chế phẩm Mixin. Bạn có thể dễ dàng mở rộng nhiều mixin, vd A extends B(C(D)). Đây là sự tuyến tính hóa rõ ràng của các mixin mà tôi đã nói ở trên, ví dụ như bạn đang soạn thảo một hệ thống phân cấp kế thừa một cách hiệu quả A -> B -> C -> D.

Trong các trường hợp khác, ví dụ: khi bạn muốn soạn Mixins trên một lớp hiện có, bạn có thể áp dụng Mixin như sau:

const MyClassWithMixin = MyMixin(MyClass);

Tuy nhiên, tôi thấy cách đầu tiên hoạt động tốt nhất ComponentsDirectives, vì chúng cũng cần được trang trí bằng @Componenthoặc @Directivedù sao đi nữa.


điều này thật tuyệt! cám ơn vì sự gợi ý. MixinRoot có đơn giản chỉ được sử dụng như một trình giữ chỗ lớp trống ở đây không? chỉ muốn chắc chắn rằng sự hiểu biết của tôi là chính xác.
Alex Lockwood

@AlexLockwood yup, trình giữ chỗ lớp trống chính xác là những gì tôi đang sử dụng nó cho. Tôi vui vẻ tránh sử dụng nó nhưng bây giờ tôi không tìm thấy cách nào tốt hơn để làm điều đó.
Julian Rudolph

2
Tôi đã kết thúc bằng cách sử dụng function Destroyable<T extends Constructor<{}>>(Base = class { } as T). Bằng cách đó tôi có thể tạo mixins bằng cách sử dụng extends Destroyable().
Alex Lockwood

1
Điều này có vẻ rất tốt, tuy nhiên dường như AoT build (Cli1.3) sẽ loại bỏ ngOnDestroy khỏi DashBoardComponent vì nó không bao giờ được gọi. (tương tự với ngOnInit)
dzolnjan

cảm ơn vì giải pháp này Tuy nhiên, sau khi xây dựng prod với ion hoặc angular-cli, mixin không hoạt động bằng cách nào đó, như thể nó chưa được mở rộng.
Han Che

16

cập nhật

Kế thừa thành phần được hỗ trợ kể từ 2.3.0-rc.0

nguyên

Cho đến nay, thuận tiện nhất đối với tôi là giữ mẫu & kiểu riêng biệt thành các tệp *html& *.csstệp và chỉ định chúng thông qua templateUrlstyleUrlsđể dễ dàng sử dụng lại.

@Component {
    selector: 'my-panel',
    templateUrl: 'app/components/panel.html', 
    styleUrls: ['app/components/panel.css']
}
export class MyPanelComponent extends BasePanelComponent

2
Đây chính xác là những gì tôi cần. Trình trang trí @Component sẽ trông như thế nào đối với BasePanelComponent? Nó có thể tham chiếu các tệp html / css khác nhau không? Nó có thể tham chiếu các tệp html / css tương tự được tham chiếu bởi MyPanelComponent không?
ebhh2001

1
Điều này không kế thừa @Input()@Output()trang trí, phải không?
Leon Adler

10

Theo như tôi biết kế thừa thành phần chưa được triển khai trong Angular 2 và tôi không chắc họ có kế hoạch hay không, tuy nhiên vì Angular 2 đang sử dụng bản thảo (nếu bạn đã quyết định đi theo con đường đó), bạn có thể sử dụng kế thừa lớp bằng cách thực hiện class MyClass extends OtherClass { ... }. Để kế thừa thành phần, tôi khuyên bạn nên tham gia vào dự án Angular 2 bằng cách truy cập https://github.com/angular/angular/issues và gửi yêu cầu tính năng!


Có nó, tôi sẽ thử trong những ngày tiếp theo lặp lại dự án angular2 và xác minh tính năng yêu cầu không còn trong các vấn đề dự án trong Git và nếu không tôi sẽ đưa ra yêu cầu về tài nguyên, vì nó có vẻ rất thú vị đặc tính. Bất kỳ ý tưởng tranh luận thêm để thực hiện các yêu cầu thú vị nhất?
Fernando Leal

1
Về bản thảo của tài nguyên thừa kế mà tôi đã sử dụng trong giải pháp ban đầu của tôi ( export class MyPanelComponent extends BasePanelComponent), vấn đề chỉ xảy ra trong trường hợp Chú thích / Trang trí không được kế thừa.
Fernando Leal

1
Vâng, tôi thực sự không biết những gì bạn có thể thêm. Tôi thích ý tưởng về việc có một trình trang trí mới (đại loại như @SubComponent()) đánh dấu một lớp là một thành phần con hoặc có thêm một trường trên trình @Componenttrang trí cho phép bạn tham chiếu một thành phần cha mẹ để kế thừa từ đó.
watzon

1
Yêu cầu tính năng angular2 được thêm vào dự án trên GitHub: Mở rộng / Kế thừa các chú thích thành phần angular2 # 7968
Fernando Leal

9

Hãy cho chúng tôi hiểu một số hạn chế và tính năng chính trên hệ thống kế thừa thành phần của Angular.

Thành phần chỉ kế thừa logic lớp:

  • Tất cả dữ liệu meta trong trình trang trí @Component không được kế thừa.
  • Thuộc tính thành phần @Input và thuộc tính @Output được kế thừa.
  • Vòng đời thành phần không được kế thừa.

Những tính năng này rất quan trọng cần có trong tâm trí, vì vậy chúng ta hãy kiểm tra từng cái một cách độc lập.

Thành phần chỉ kế thừa logic lớp

Khi bạn kế thừa một Thành phần, tất cả logic bên trong đều được kế thừa như nhau. Điều đáng chú ý là chỉ có các thành viên công cộng được thừa kế là thành viên tư nhân chỉ có thể truy cập trong lớp thực hiện chúng.

Tất cả dữ liệu meta trong trình trang trí @Component không được kế thừa

Thực tế là ban đầu không có dữ liệu meta nào có vẻ phản trực giác, nhưng nếu bạn nghĩ về điều này thì nó thực sự có ý nghĩa hoàn hảo. Nếu bạn thừa kế từ Thành phần nói (thành phầnA), bạn sẽ không muốn bộ chọn của Thành phần, mà bạn đang kế thừa để thay thế bộ chọn của Thành phần là lớp kế thừa. Điều tương tự có thể được nói cho mẫu / templateUrl cũng như style / styleUrls.

Các thuộc tính thành phần @Input và @Output được kế thừa

Đây là một tính năng khác mà tôi thực sự yêu thích về Kế thừa thành phần trong Angular. Trong một câu đơn giản, bất cứ khi nào bạn có thuộc tính @Input và @Output tùy chỉnh, các thuộc tính này sẽ được kế thừa.

Vòng đời thành phần không được kế thừa

Phần này là một phần không quá rõ ràng đặc biệt là với những người không làm việc rộng rãi với các nguyên tắc OOP. Ví dụ: giả sử bạn có ElementA thực hiện một trong nhiều móc vòng đời của Angular như OnInit. Nếu bạn tạo Thành phần và kế thừa Thành phần, vòng đời OnInit từ Thành phần sẽ không kích hoạt cho đến khi bạn gọi nó một cách rõ ràng ngay cả khi bạn có vòng đời OnInit này cho Thành phần.

Gọi các phương thức thành phần siêu / cơ sở

Để có phương thức ngOnInit () từ lửa ElementA, chúng ta cần sử dụng siêu từ khóa và sau đó gọi phương thức chúng ta cần trong trường hợp này là ngOnInit. Siêu từ khóa đề cập đến thể hiện của thành phần đang được kế thừa từ đó trong trường hợp này sẽ là Thành phần.


5

nếu bạn đọc qua các thư viện CDK và thư viện vật liệu, họ đang sử dụng tính kế thừa nhưng không nhiều cho bản thân các thành phần, phép chiếu nội dung là vua IMO. xem liên kết này https://blog.angular-university.io/angular-ng-content/ nơi nó nói "vấn đề chính với thiết kế này"

Tôi biết điều này không trả lời câu hỏi của bạn nhưng tôi thực sự nghĩ rằng nên tránh các thành phần kế thừa / mở rộng . Đây là lý do của tôi:

Nếu lớp trừu tượng được mở rộng bởi hai hoặc nhiều thành phần chứa logic được chia sẻ: sử dụng một dịch vụ hoặc thậm chí tạo một lớp bản thảo mới có thể được chia sẻ giữa hai thành phần.

Nếu lớp trừu tượng ... chứa các biến được chia sẻ hoặc các hàm onClicketc, thì sẽ có sự trùng lặp giữa html của hai khung nhìn thành phần mở rộng. Đây là một thực tiễn tồi tệ và html được chia sẻ cần được chia thành các Thành phần. Các thành phần (bộ phận) này có thể được chia sẻ giữa hai thành phần.

Tôi có thiếu các lý do khác để có một lớp trừu tượng cho các thành phần không?

Một ví dụ tôi thấy gần đây là các thành phần mở rộng AutoUnsubscribe:

import { Subscription } from 'rxjs';
import { OnDestroy } from '@angular/core';
export abstract class AutoUnsubscribeComponent implements OnDestroy {
  protected infiniteSubscriptions: Array<Subscription>;

  constructor() {
    this.infiniteSubscriptions = [];
  }

  ngOnDestroy() {
    this.infiniteSubscriptions.forEach((subscription) => {
      subscription.unsubscribe();
    });
  }
}

điều này là cơ bản vì trong suốt một cơ sở mã lớn, infiniteSubscriptions.push()chỉ được sử dụng 10 lần. Ngoài ra, nhập và mở rộng AutoUnsubscribethực sự cần nhiều mã hơn là chỉ thêm mySubscription.unsubscribe()vào ngOnDestroy()phương thức của chính thành phần, điều này đòi hỏi logic bổ sung.


Ok, tôi hiểu sự sắp xếp của bạn và tôi đồng ý rằng tập hợp gần như giải quyết tất cả các vấn đề dường như cần sự kế thừa. Và thật thú vị khi nghĩ về các thành phần như những phần nhỏ của ứng dụng có thể được cập cảng theo nhiều cách khác nhau. Nhưng trong trường hợp câu hỏi, vấn đề là tôi không có quyền kiểm soát / quyền truy cập vào các sửa đổi trong thành phần tôi muốn kế thừa (nó là thành phần thứ ba), thì tổng hợp sẽ trở nên không khả thi và kế thừa sẽ là giải pháp lý tưởng.
Fernando Leal

Tại sao bạn không thể tạo một thành phần mới đóng gói thành phần bên thứ ba đó? Thành phần bên thứ ba của bạn không quan tâm là gì? ví dụ: <my-calendar [Stuff] = Stuff> <third-party-calendar [Stuff] = Stuff> </ ..> </ ..>
robert king

@robertking lặp lại chính mình là mô hình rất yếu ... Đó là lý do tại sao bạn sẽ bắt đầu ghét công việc của mình .. thay vì tận hưởng nó.
Dariusz Filipiak

Đối với tôi, đó là một ý tưởng tốt để mở rộng các thành phần trong trường hợp bạn muốn có cùng thông số Đầu vào / Đầu ra cho một tập hợp các thành phần, để chúng có thể hoạt động như một. Ví dụ: tôi có một số bước đăng ký (certsStep, addressStep, selectBenefitsStep). Tất cả chúng nên có cùng tùy chọn Đầu vào (stepName, actionButtons ...) và Đầu ra (hoàn thành, hủy bỏ).
Sergey_T

@Sergey_T bạn có thể xem xét một thành phần với ng chọn và chiếu nội dung không? Ngoài ra, việc lặp lại một vài yếu tố đầu vào có vẻ như bạn không thực sự tiết kiệm nhiều TBH chức năng.
vua Robert

2

Nếu bất cứ ai đang tìm kiếm một giải pháp cập nhật, câu trả lời của Fernando là khá hoàn hảo. Ngoại trừ điều đó ComponentMetadatađã bị phản đối. Sử dụng Componentthay vì làm việc cho tôi.

Tệp trang trí tùy chỉnh đầy đủ CustomDecorator.tstrông như thế này:

import 'zone.js';
import 'reflect-metadata';
import { Component } from '@angular/core';
import { isPresent } from "@angular/platform-browser/src/facade/lang";

export function CustomComponent(annotation: any) {
  return function (target: Function) {
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);

    var parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key => {
      if (isPresent(parentAnnotation[key])) {
        // verify is annotation typeof function
        if(typeof annotation[key] === 'function'){
          annotation[key] = annotation[key].call(this, parentAnnotation[key]);
        }else if(
          // force override in annotation base
          !isPresent(annotation[key])
        ){
          annotation[key] = parentAnnotation[key];
        }
      }
    });

    var metadata = new Component(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
  }
}

Sau đó nhập nó vào sub-component.component.tstệp thành phần mới của bạn và sử dụng @CustomComponentthay vì @Componentnhư thế này:

import { CustomComponent } from './CustomDecorator';
import { AbstractComponent } from 'path/to/file';

...

@CustomComponent({
  selector: 'subcomponent'
})
export class SubComponent extends AbstractComponent {

  constructor() {
    super();
  }

  // Add new logic here!
}

Là trang trí tùy chỉnh không được khuyến khích cao? Từ nhiều bài đăng / chủ đề khác, giải pháp này đã bị đánh dấu là hoàn toàn sai vì AOT sẽ không hỗ trợ họ?
TerNovi

2

Bạn có thể kế thừa @Input, @Output, @ViewChild, v.v. Hãy xem mẫu:

@Component({
    template: ''
})
export class BaseComponent {
    @Input() someInput: any = 'something';

    @Output() someOutput: EventEmitter<void> = new EventEmitter<void>();

}

@Component({
    selector: 'app-derived',
    template: '<div (click)="someOutput.emit()">{{someInput}}</div>',
    providers: [
        { provide: BaseComponent, useExisting: DerivedComponent }
    ]
})
export class DerivedComponent {

}

1

Các thành phần có thể được mở rộng giống như một kế thừa lớp bản thảo, chỉ là bạn phải ghi đè bộ chọn bằng một tên mới. Tất cả các thuộc tính Input () và Output () từ Thành phần gốc hoạt động như bình thường

Cập nhật

@Component là một trang trí,

Trang trí được áp dụng trong quá trình khai báo lớp không trên các đối tượng.

Về cơ bản, các trình trang trí thêm một số siêu dữ liệu vào đối tượng lớp và không thể truy cập thông qua kế thừa.

Nếu bạn muốn đạt được Kế thừa trang trí, tôi sẽ đề nghị viết một trang trí tùy chỉnh. Một cái gì đó như ví dụ dưới đây.

export function CustomComponent(annotation: any) {
    return function (target: Function) {
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;

    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
    var parentParamTypes = Reflect.getMetadata('design:paramtypes', parentTarget);
    var parentPropMetadata = Reflect.getMetadata('propMetadata', parentTarget);
    var parentParameters = Reflect.getMetadata('parameters', parentTarget);

    var parentAnnotation = parentAnnotations[0];

    Object.keys(parentAnnotation).forEach(key => {
    if (isPresent(parentAnnotation[key])) {
        if (!isPresent(annotation[key])) {
        annotation[key] = parentAnnotation[key];
        }
    }
    });
    // Same for the other metadata
    var metadata = new ComponentMetadata(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
    };
};

Tham khảo: https://medium.com/@ttemplier/angular2-decorators-and-group-inherribution-905921dbd1b7


Bạn có thể làm gương (sử dụng ví dụ của câu hỏi) nó sẽ hoạt động như thế nào? Bạn có thể sử dụng stackblitz để phát triển ví dụ và chia sẻ liên kết.
Fernando Leal

@Component là một trang trí, trang trí được áp dụng trong quá trình khai báo lớp không trên các đối tượng.
MAHESH VALIYA VEETIL

Bạn đúng rồi. Trang trí không làm cho bất kỳ sự khác biệt. Nó chỉ được yêu cầu nếu thành phần cơ sở được sử dụng làm thành phần ở một nơi khác
MAHESH VALIYA VEETIL

0
just use inheritance,Extend parent class in child class and declare constructor with parent class parameter and this parameter use in super().

1.parent class
@Component({
    selector: 'teams-players-box',
    templateUrl: '/maxweb/app/app/teams-players-box.component.html'
})
export class TeamsPlayersBoxComponent {
    public _userProfile:UserProfile;
    public _user_img:any;
    public _box_class:string="about-team teams-blockbox";
    public fullname:string;
    public _index:any;
    public _isView:string;
    indexnumber:number;
    constructor(
        public _userProfilesSvc: UserProfiles,
        public _router:Router,
    ){}
2.child class
@Component({

    selector: '[teams-players-eligibility]',
    templateUrl: '/maxweb/app/app/teams-players-eligibility.component.html'
})
export class TeamsPlayersEligibilityComponent extends TeamsPlayersBoxComponent{

    constructor (public _userProfilesSvc: UserProfiles,
            public _router:Router) {
            super(_userProfilesSvc,_router);
        }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.