컴포넌트를 확장/상속하는 방법
기본 컴포넌트가 변경될 수 있기 때문에 Angular 2에 이미 배치된 컴포넌트 중 일부를 완전히 다시 작성할 필요 없이 확장 버전을 만들고 싶습니다.
이 간단한 예제를 작성했습니다.내 질문을 더 잘 설명하기 위해서입니다.
요소 포함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);
}
}
파생 를 들어, 기본 를 들어, 에서는 기본 컴포넌트의 을 변경할 수 있습니다.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";
}
}
주의: 이 예는 분명 단순하며 그렇지 않으면 상속을 사용할 필요가 없습니다.그러나 이는 실제 문제를 설명하기 위한 것입니다.
컴포넌트 에서 알 수app/my-panel.component.ts 계승된 은 「이것」, 「은 '이것'입니다class BasePanelComponent ,는@Component 부분만 것이 . 단순히 변경된 부분뿐만 아니라selector: 'my-panel'.
"Angular2" 상속하여 "Angular2"를 상속할 수 있는 ?class예: '마킹/표기@Component
편집 1 - 기능 요청
GitHub의 프로젝트에 추가된 기능 요청 angular2: 확장/상속 angular2 컴포넌트 주석 #7968
편집 2 - 마감된 요청
이 때문에 데코레이터의 결합 방법을 짧게 알 수 없는 요청이 종료되었습니다.선택의 여지가 없는 거죠그래서 내 의견은 그 이슈에 인용되었다.
대체 솔루션:
티에리 템플리어의 이 답변은 문제를 해결할 수 있는 대안이다.
Tierry Templier와 몇 가지 질문을 한 후, 저는 이 질문에서 언급된 상속 제한의 대안으로 제 기대에 부합하는 다음과 같은 작업 예를 들었습니다.
1 - 커스텀 데코레이터 작성:
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 - 기본 컴포넌트(@Component decorator):
@Component({
// create seletor base for test override property
selector: 'master',
template: `
<div>Test</div>
`
})
export class AbstractComponent {
}
3 - @Custom Component 데코레이터를 사용하는 서브 컴포넌트:
@CustomComponent({
// override property annotation
//selector: 'sub',
selector: (parentSelector) => { return parentSelector + 'sub'}
})
export class SubComponent extends AbstractComponent {
constructor() {
}
}
Angular의 컴포넌트 상속 시스템에 관한 몇 가지 주요 제한과 기능에 대해 설명합니다.
컴포넌트는 클래스 로직만 상속합니다.
- @Component 데코레이터의 모든 메타데이터는 상속되지 않습니다.
- 컴포넌트 @Input 속성 및 @Output 속성이 상속됩니다.
- 구성 요소 수명 주기가 상속되지 않습니다.
이러한 기능은 매우 중요하므로 각각 개별적으로 살펴보겠습니다.
구성 요소는 클래스 로직만 상속합니다.
구성요소를 상속하면 내부의 모든 논리가 동일하게 상속됩니다.개인 구성원은 구현된 클래스에서만 액세스할 수 있으므로 공용 구성원만 상속됩니다.
@Component 데코레이터의 모든 메타데이터는 상속되지 않습니다.
메타 데이터가 상속되지 않는다는 사실은 처음에는 직관에 반하는 것처럼 보일 수 있지만, 이 점을 생각해 보면 완벽하게 이해가 됩니다.컴포넌트 예(componentA)에서 상속하는 경우 상속되는 컴포넌트A의 셀렉터가 상속되는 클래스인 컴포넌트B의 셀렉터를 대체하지 않도록 할 수 있습니다.template/templateUrl뿐만 아니라 style/StyleUrl도 마찬가지입니다.
컴포넌트 @Input 및 @Output 속성이 상속됩니다.
이것은 또한 Inheritance in Angular 컴포넌트에 대해 매우 좋아하는 기능입니다.간단히 말하면 커스텀 @Input 속성 및 @Output 속성이 있을 때마다 이러한 속성이 상속됩니다.
구성 요소 수명 주기가 상속되지 않음
이 부분은 특히 OOP 원칙을 광범위하게 적용하지 않은 사람들에게는 그다지 명확하지 않은 부분입니다.예를 들어 OnInit와 같은 Angular의 많은 라이프 사이클 훅 중 하나를 구현하는 ComponentA가 있다고 가정합니다.Component B를 만들고 Component A를 상속하는 경우 Component B의 OnInit 라이프 사이클이 있어도 Component A의 OnInit 라이프 사이클이 명시적으로 호출될 때까지 실행되지 않습니다.
슈퍼/베이스 컴포넌트 메서드 호출
ComponentA에서 ngOnInit() 메서드를 기동하려면 super 키워드를 사용하여 필요한 메서드를 호출해야 합니다.이 경우 ngOnInit입니다.super 키워드는 상속되는 컴포넌트의 인스턴스를 나타냅니다.이 경우 ComponentA가 됩니다.
Angular 2 버전 2.3은 최근에 출시되었으며 기본 구성 요소 상속이 포함되어 있습니다.템플릿 및 스타일을 제외하고 원하는 모든 항목을 상속 및 재정의할 수 있습니다.참고 자료:
갱신하다
원래의
까지의 나에게 가장 편리한 것은 입니다.*html&*.css하고, 「파일」을 사용해 지정합니다.templateUrl ★★★★★★★★★★★★★★★★★」styleUrls재사용이 용이합니다.
@Component {
selector: 'my-panel',
templateUrl: 'app/components/panel.html',
styleUrls: ['app/components/panel.css']
}
export class MyPanelComponent extends BasePanelComponent
이제 TypeScript 2.2는 클래스 식에서 Mixins를 지원하므로 컴포넌트에서 Mixins를 훨씬 더 잘 표현할 수 있게 되었습니다.각진 2.3(토론) 이후 구성요소 상속 또는 여기서 설명하는 사용자 정의 장식기를 사용할 수도 있습니다.단, Mixin에는 컴포넌트 전체의 동작을 재사용하기 위한 몇 가지 특성이 있다고 생각합니다.
- 믹스인은 보다 유연하게 구성되며, 기존 컴포넌트에 믹스인을 조합하거나 믹스인을 조합하여 새로운 컴포넌트를 형성할 수 있습니다.
- 클래스 상속 계층에 대한 명백한 선형화로 인해 믹스인 구성은 이해하기 쉬운 상태로 유지됩니다.
- 컴포넌트 상속(토론)을 방해하는 데코레이터와 주석을 사용하면 문제를 쉽게 방지할 수 있습니다.
위의 TypeScript 2.2 발표를 읽고 Mixins의 구조를 이해할 것을 강력히 권장합니다.각진 GitHub 문제에 대한 링크된 논의는 추가 세부사항을 제공합니다.
다음과 같은 유형이 필요합니다.
export type Constructor<T> = new (...args: any[]) => T;
export class MixinRoot {
}
.Destroyable가 에서 하는 데 이 되는 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
}
};
}
DestroyableComponent 자신의
export class DashboardComponent extends Destroyable(MixinRoot)
implements OnInit, OnDestroy { ... }
:MixinRoot한 것은, 꼭 한 것은, 라고 하는 입니다.extend을 쉽게 할 수 . 예를 여러믹스인을 쉽게 할 수 있습니다.A extends B(C(D))를 들어 상속 .예를 들어 상속 계층을 효과적으로 구성하고 있습니다.A -> B -> C -> D.
예를 들어 기존 클래스에서 Mixin을 작성하려는 경우 다음과 같이 Mixin을 적용할 수 있습니다.
const MyClassWithMixin = MyMixin(MyClass);
하지만 첫 번째 방법이 가장 효과적이라는 것을 알게 되었습니다.Components ★★★★★★★★★★★★★★★★★」Directives, 이것들은 「이것들」로 가 있기 @Component ★★★★★★★★★★★★★★★★★」@Directive★★★★★★★★★★★★★★★★★★.
되지 않은 있으며,는 (루트를 선택한 타이프스크립트를에 Angular 2를 상속을 할 수 .상속을 사용할 수 있습니다.class MyClass extends OtherClass { ... }컴포넌트 상속을 위해서는 https://github.com/angular/angular/issues에 접속하여 기능 요청을 제출하여 Angular 2 프로젝트에 참여할 것을 권장합니다.
CDK 라이브러리와 재료 라이브러리를 읽어보면 컴포넌트 자체에는 그다지 많지 않지만 상속을 사용하고 있습니다.콘텐츠 투사에는 IMO가 포함됩니다.이 링크에는 "이 설계의 주요 문제"가 기재되어 있습니다.https://blog.angular-university.io/angular-ng-content/
이것이 당신의 질문에 답하지 못한다는 것을 알지만, 저는 정말로 컴포넌트를 상속/확장하는 것을 피해야 한다고 생각합니다.제 이유는 이렇습니다.
둘 이상의 컴포넌트에 의해 확장된 추상 클래스에 공유 로직이 포함되어 있는 경우, 서비스를 사용하거나 두 컴포넌트 간에 공유할 수 있는 새로운 타입 스크립트클래스를 만듭니다.
추상수업이...에는 공유 변수 또는 onClicketc 함수가 포함되어 있습니다.그러면 두 확장 컴포넌트 뷰의 html 사이에 중복이 발생합니다.이는 잘못된 관행으로 공유 html을 컴포넌트로 분할해야 합니다.이들 컴포넌트(부품)는 2개의 컴포넌트 간에 공유할 수 있습니다.
컴포넌트에 대한 추상 클래스를 수강해야 하는 다른 이유가 누락되어 있습니까?
최근에 본 예로는 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();
});
}
}
은 큰 베이스 「Code Base」가 존재했기 때문입니다.infiniteSubscriptions.push()10월 10일Import 및 확장도 가능AutoUnsubscribe를 더하는 보다 더 를 사용합니다.mySubscription.unsubscribe() ngOnDestroy()컴포넌트 자체의 메서드(어차피 추가 로직이 필요).
업데이트된 솔루션을 찾는 사람이 있다면 페르난도의 답변은 거의 완벽합니다., 그 이외에는ComponentMetadata을 사용하다「」를 사용합니다.Component대신 저를 위해 일했어요.
데코레이터CustomDecorator.ts을 사용하다
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);
}
}
다음 새 컴포넌트로 . Importsub-component.component.ts하여 사용하다. " 를 사용합니다.@CustomComponent@Component음음음같 뭇매하다
import { CustomComponent } from './CustomDecorator';
import { AbstractComponent } from 'path/to/file';
...
@CustomComponent({
selector: 'subcomponent'
})
export class SubComponent extends AbstractComponent {
constructor() {
super();
}
// Add new logic here!
}
선택기를 새 이름으로 재정의해야 하는 경우에만 구성 요소를 형식 스크립트 클래스 상속과 동일하게 확장할 수 있습니다.부모 컴포넌트의 모든 Input() 및 Output() 속성은 정상적으로 동작합니다.
갱신하다
@컴포넌트는 데코레이터입니다.
데코레이터는 객체가 아닌 클래스 선언 중에 적용됩니다.
기본적으로 데코레이터는 클래스 개체에 일부 메타데이터를 추가하고 상속을 통해 액세스할 수 없습니다.
만약 당신이 데코레이터 상속을 얻고 싶다면, 나는 커스텀 데코레이터를 쓰는 것을 제안합니다.예를 들면 다음과 같습니다.
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);
};
};
참조처: https://medium.com/ @ttemplier / param2-supervators-and-class-dbd1b7
@Input, @Output, @ViewChild 등을 상속할 수 있습니다.샘플을 보세요.
@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 {
}
상속 사용, 자식 클래스의 부모 클래스 확장 및 부모 클래스 매개 변수와 이 매개 변수 사용을 선언하는 생성자만 사용하십시오.super().
- 부모 클래스:
@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,
){}
- 자녀 클래스:
@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);
}
}
언급URL : https://stackoverflow.com/questions/36475626/how-to-extend-inherit-components
'source' 카테고리의 다른 글
| 문서 배열의 개체를 업데이트하려면 어떻게 해야 합니까(내포된 업데이트) (0) | 2023.03.04 |
|---|---|
| 캔버스 및 각도 작업JS (0) | 2023.03.04 |
| mongorestore 오류:덤프 파일을 어떻게 해야 할지 모르겠어요. (0) | 2023.03.04 |
| p:dataTable에서 필터를 사용할 때 Ajax 업데이트가 작동하지 않음 (0) | 2023.03.04 |
| Mongoose, find가 있는 특정 필드를 선택합니다. (0) | 2023.03.04 |