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
我不确定这是否正是你需要的,但我尝试写了一个小的解决方案,用来与你的示例进行一般的组件交互,
- 在你的卡片组件中,
添加一个我们以后可以从主应用组件使用的输入,
@Input('complexInput') complexInputContent: string;
然后将 innerHTML 初始化为添加的全局输入,
let innerHTML = this.complexInputContent;
- 按如下更新你的应用组件,
<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 中。但它却相当有效地完成了任务。
