网站搜索

javascript - Angular 2/4/5/6 - 在组件类端转换自定义组件的 innerHTML


我想制作以下基本组件:card.component,让它能将用户在其 innerHTML 上定义的内容传入组件类,以便它可以对其进行转换并在模板中显示。

用户将这样使用此组件:

<app-card>hello world, this is a sample text</app-card>

这里有一个在 StackBlitz.com 上的基础项目,你可以分叉它来使其工作。

https://stackblitz.com/edit/angular-cmdpgh?file=src/app/components/card/card.component.ts

这里是代码的预览:

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-card',
    templateUrl: 'card.component.html',
    styleUrls: [ 'card.component.css' ],
})
export class CardComponent implements OnInit {

  private content: string;

  ngOnInit() {
    // please, override this to get the real innerHTML on: 'app.component.html'
    let innerHTML = 'testing';
    this.content = CardComponent.complexStrTransform(innerHTML);
  }
  private static complexStrTransform(str: string): string {
    // complex transformations here
    let result = '';
    for (let i = 0; i < str.length; i++) {
      let c = str[i];
      result += c;
      result += c.toUpperCase();
      result += '|';
    }
    result = '!!!' + result + '!!!';
    return result;
  }
}
<mat-card>
    <mat-card-content>
        {{content}}
    </mat-card-content>
    <mat-card-actions>
        <button mat-button>LIKE</button>
        <button mat-button>SHARE</button>
    </mat-card-actions>
</mat-card>

在位置 {{content}} 上,组件应显示 complexStrTransform(...) 的结果。

我在一些地方看到可以使用:<ng-content></ng-content> 来指定组件模板中想要放置 innerHTML 的位置,但我认为这在这里不是最好的选择,因为我需要对 innerHTML 进行非常复杂的转换,而这些转换只能在组件类中完成。

有什么建议吗?

感谢您的关注。

答案#1

我不确定这是否正是你需要的,但我尝试写了一个小的解决方案,用来与你的示例进行一般的组件交互,

  1. 在你的卡片组件中,

添加一个我们以后可以从主应用组件使用的输入,

 @Input('complexInput') complexInputContent: string;

然后将 innerHTML 初始化为添加的全局输入,

 let innerHTML = this.complexInputContent;
  1. 按如下更新你的应用组件,

<app-card  [complexInput]="contentDiv.innerText">


<div #contentDiv contenteditable="true" >

hello world, this is a sample text

</div>


</app-card>

这是工作解决方案(预览):https://angular-k5wjbp.stackblitz.io/

可编辑代码:https://stackblitz.com/edit/angular-k5wjbp

参考资料:https://angular.io/guide/component-interaction

答案#2

Dilusha之前的回答完成了部分工作。另一部分是将你的transform函数实现为管道,并使用一些DOM技巧。这是在Stackblitz上的示例。

首先,将你的 transform 函数重写为 Pipe(并重构组件):

import { Component, Pipe, PipeTransform } from '@angular/core';

@Component({
  selector: 'app-card',
  templateUrl: 'card.component.html',
  styleUrls: ['card.component.css'],
})
export class CardComponent { }

@Pipe({ name: 'complexStr' })
export class ComplexStrPipe implements PipeTransform {
  transform(str: string): string {
    // complex transformations here
    let result = '';
    for (let i = 0; i < str.length; i++) {
      let c = str[i];
      result += c;
      result += c.toUpperCase();
      result += '|';
    }
    result = '!!!' + result + '!!!';
    return result;
  }
}

接下来,在你的组件中添加 ng-content 标签,这样用户就可以轻松插入内容。同时,使用 display: none 样式将其隐藏,并分配一个模板引用变量,以便你的组件可以访问它并使用管道显示它:

<mat-card>
    <mat-card-content>
        {{inner.innerText | complexStr}}
    </mat-card-content>
    <mat-card-actions>
        <button mat-button>LIKE</button>
        <button mat-button>SHARE</button>
    </mat-card-actions>
</mat-card>
<div #inner style="display: none">
    <ng-content></ng-content>
</div>

现在你的组件可以按预期工作了:

<app-card>hello world, this is a sample text</app-card>

这显然有点像是一个临时作法,因为原始的用户内容仍然存在于 DOM 中。但它却相当有效地完成了任务。