Angular组件继承和订阅继承

5
以下是一个组件,我将在其他各种组件中进行扩展以重用一些代码。
import { Component } from '@angular/core';

@Component ({
   selector: 'my-app',
   template: ` <div>
      <h1>{{appTitle}}</h1>
      <div>To Tutorials Point</div>
   </div> `,
})

export class AppComponent {
   appTitle: string = 'Welcome';
   ngOnInit(){
      this.registerSomeSubscriptions();
   }
   registerSomeSubscriptions(){
      this.subscribeSomething.subscribe((data)=>{
         performSomeAction();
      })
   }


}

我可以像下面这样扩展它。
 import { Component } from '@angular/core';

@Component ({
   selector: 'my-app',
   template: ` <div>
      <h1>{{appTitle}}</h1>
      <div>To Tutorials Point</div>
   </div> `,
})

export class ChildComponent extends AppComponent {
   
}

虽然我知道组件的公共成员将在子组件中可用。

我的问题

  1. 我是否仍需要为两个组件使用单独的HTML文件,或者是否有某种代码风格或问题解决技术可重复使用相同的HTML模板,并含有一些特定于子级实现的内容,这是我不知道的技术?

你可以使用指令来设置订阅,指令可以通过 Host 访问宿主组件的方法和值。https://angular.io/api/core/Host - glued
你到底想要什么?如果你只是想重复使用同一个模板,你可以将它放在一个HTML文件中,并从你的子组件中引用它。 - David
@David 不要重复使用,也许我有点超前了,但是当我们谈论继承时,我们指的是扩展一些现有的功能,我们可以在ts文件中扩展组件,但是子组件需要一个单独的html文件,我的问题是,如果该子html只是父组件html的扩展,但我仍然必须从父组件复制html。然而,从下面的答案和Rnd来看,似乎没有像html这样的继承方式,视图在angular中是分开引用的,这使得新开发人员难以理解代码。 - nobalG
@nobalG 你想要它只是像模板HTML一样,还是你也想把属性(如appTitle)移动到父组件并通过子组件传递值? - wessam yaacob
5个回答

2

子组件可以使用与父组件相同的html模板,也可以拥有自己的html文件,这种情况下,父组件的html将不会被使用。

如果您想在子组件中使用父组件的html并进行一些修改,您可以重新使用父组件而不是继承它。

  • 将您的父组件创建为可重用组件
  • 在子/特征组件的模板中,使用其选择器添加父组件
    // add something specific to child/feature component here
    <app-reusable-component></app-reusable-component>
    // add something specific to child/feature component here

可重用组件的HTML将与您在功能组件的HTML中添加的其他HTML一起提供。
要在可重用组件和功能组件之间传递数据,请使用组件交互- InputOutputInput- 使用输入绑定将数据从功能组件传递到可重用组件。
reusable-component.ts:
export class ReusableComponent implements OnInit {
   @Input() dataIn: Observable<object>;
   ngOnInit() {
     dataIn.subscribe(data => {
       // display data
     });
   }
}

feature-component.html:
...
<app-reusable-component [dataIn]="dataToDisplay$"></app-reusable-component>
...

feature-component.ts:
export class FeatureComponent implements OnInit {
  public dataToDisplay$: Observable<object>;
  ngOnInit() {
    this.dataToDisplay$ = this.http.get(url);
  }
}
  • 输出 - 将数据/事件从可重用组件发送到功能组件
reusable-component.ts:
export class ReusableComponent implements OnInit {
   @Input() dataIn: Observable<object>;
   @Output() eventOut: EventEmitter<object> = new EventEmitter<object>();
   ngOnInit() {
     dataIn.subscribe(data => {
       // display data
     });
   }
   userInput(value) {
      this.eventOut.emit(value);
   }
}

feature-component.html:
...
<app-reusable-component [dataIn]="dataToDisplay$" (eventOut) ="handleUserData($event)"></app-reusable-component>
...

feature-component.ts:
export class FeatureComponent implements OnInit {
  public dataToDisplay$: Observable<object>;
  ngOnInit() {
    this.dataToDisplay$ = this.http.get(url);
  }
  handleUserData(value) {
    this.http.post(url, value);
  }
}

在这种方法中,您可以在所有子/特性组件中重用父组件的模板,并且您将能够在子/特性组件中添加额外的HTML内容并在它们之间传递数据。

1
如果您只想为子组件和父组件重用相同的模板,则只需将该模板放入html文件中,并使用templateUrl进行引用。您的订阅将被继承,您将能够从子组件访问公共受保护和受保护的变量。
现在,如果您想继承父模板但能够进行模板修改,则有点困难,因为angular不提供模板继承。
一个可能的替代方案是使用模板引擎生成html。在我们的一个项目中,我们使用nunjucks解决了这个限制。
因此,基本上,您可以使用nunjucks模板指定父组件的html。

parent.component.html.njk

<div>

Parent template

{% block specific %}
{% endblock %}

</div>

parent.component.ts

@Component ({
   selector: 'app-parent',
   templateUrl: `parent.component.html`, //Reference compiled template (not .njk)
})
export class ParentComponent
{
    //...
    

然后您还需要将子组件定义为一个 nunjucks 模板,该模板继承自父模板

child.component.html.njk

{% extends '/path/to/parent/parent.component.html.njk' %}

{% block specific %}
  Child content: {{childContent}}
{%endblock %}

child.component.ts

@Component ({
   selector: 'app-child',
   templateUrl: `child.component.html`, //reference .html, not .njk
})
export class ChildComponent extends ParentComponent
{
  public childContent = "hello";

  //Access to public/protected members and methods from parent componenent
   
  

此外,我们还有一个基本的手表脚本,监视 .njk 文件的更改并生成相应的 html。

watch.js

const nunjucks = require('nunjucks');

//Nunjuck config to use <$ and $> for tags, instead of {{ and }}, to avoid conflicting with angular
const nunjucksEnv = nunjucks.configure(
  {
    noCache: true,

    tags:
      {
        variableStart: '<$',
        variableEnd: '$>',
      }
  }
);

//Add watch loop here. Whenever a njk file changes, call the code below
nunjucks.render(njkTemplateFileThatJustChanged, {}, function (err, html)
{
  if (!err)
  {
    let compiledPath = njkTemplateFileThatJustChanged.replace('.njk', '');
    fs.writeFileSync(compiledPath, html);
  }
}

0

如果模板在文件中,您可以重复使用它。 @Component 是一个装饰器,为“组件”分配一些“元”数据,因此您不会从扩展类继承它。如果模板在单独的文件中,则可以在 @Component 装饰器的 templateUrl: 属性中使用它。


0

你可能无法扩展html,但可以以多种方式利用模板:

  1. 在服务中设置基础模板的TemplateRef,使用指令以后在任何地方使用它。

    A: 缺点是基本组件需要手动实例化,并且将一直存在于内存中,直到容器处于视图中。[详见示例-BaseOneComponent]

    B: 如果模板没有太多的绑定,可以在根(AppComponent)中初始化它。

  2. 为占位符BaseTwoComponent创建一个通用组件,并使用<ng-content>从使用者组件[DerivedTwoComponent]投影数据。您还可以为<ng-content>创建多个占位符,并使用选择器与它们一起使用。 请参阅Angular Content Projection Guide,了解如何使用多个槽进行内容投影。

Stackblitz: 模板扩展


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接