在 Angular 中,我如何动态地将某些单词包装在另一个 html 元素中?

Posted

技术标签:

【中文标题】在 Angular 中,我如何动态地将某些单词包装在另一个 html 元素中?【英文标题】:In Angular how do I dynamically wrap certain words in another html element? 【发布时间】:2020-06-06 03:21:27 【问题描述】:

我有这个简单的 Angular 组件:

@Component(
  selector: 'my-component',
  template: '<p>someString</p>',
)
export class MyComponent  
  @Input() someString: string;

someString 可以是任意长度的任意字符串。例如,假设someString 的值为:

"If you want my body and you think I'm sexy, come on, sugar, tell me so."

在这种情况下,Angular 生成的 html 基本上等同于:

<p>If you want my body and you think I'm sexy, come on, sugar, tell me so.</p>

我将如何修改MyComponent,以便它检测someString 中每个出现的单词sexy,并让Angular 将该单词包装在另一个HTML 元素中,例如&lt;b&gt;。所以在这个例子中,它会产生类似的东西:

<p>If you want my body and you think I'm <b>sexy</b>, come on, sugar, tell me so.</p>

如果我想将每个出现的单词 sexy 包装在 Angular 组件中而不是原生 HTML 元素中怎么办?是否需要采用不同的方法?

【问题讨论】:

可以在句子中搜索单词,然后分别在其前后注入开始和结束标签。 @NicholasK 我如何注入开始和结束标签? 我添加了一个答案,或者与另一个答案相同。 (IMO,另一个更好!)删除了我的,因为它太复杂了.. 嗨 - 我已经完成了你的要求:包装在另一个角度标签中。这很糟糕。我最终不得不首先将尝试将文本包装在其中的角度组件(在本例中为 )导出为本机元素。找到解决问题的另一种方法将是我的建议。例如。向顶部元素添加一个 (click) 事件处理程序,并查看它是否是您包装它的 标记之一,然后执行一些操作。 【参考方案1】:

此解决方案避免使用 innerHTML 并严格依赖 Angular 构造。

@Component(
  selector: 'my-component',
  template: `
  <p>
    <ng-container *ngFor="let segment of segments">
      <span *ngIf="!segment.shouldBeBold()">segment.text</span>
      <b *ngIf="segment.shouldBeBold()">segment.text</b>
    </ng-container>
  </p>
  `,
)
export class MyComponent  
  @Input() someString: string;

  private wordsToBold = new Set(['sexy', 'body', 'sugar']); 

  get segments() 
    const regex = this.makeRegex();
    const segments = this.someString.split(regex);
    return segments.map(segment => 
      return  text: segment, shouldBeBold: wordsToBold.has(segment.toLowerCase()) ;
    );
  

  private makeRegex() 
    const expression = [...this.wordsToBold].join('\\b|\\b');
    return new RegExp(`(\\b$expression\\b)+`, 'gi');
  

【讨论】:

【参考方案2】:

你可以使用类似下面的东西——在渲染主句之后,你可以用一个 span 元素替换特殊词并应用一个 CSS 类,比如 .special 到那个 span 标签。

从 '@angular/core' 导入 Component, Input, ElementRef, AfterViewInit ;

@Component(
  selector: 'my-component',
  template: '<p>sentence</p>'
)
export class MyComponent implements AfterViewInit 
  @Input() sentence: string;
  @Input() specialWord: string;

  constructor(private el: ElementRef) 
  

  ngAfterViewInit() 
    this.el.nativeElement.innerHTML = this.el.nativeElement.
      innerHTML.replace(new RegExp(`$this.specialWord`, 'g'), 
          `<span class="special">$this.specialWord</span>`);
  


为了使您的代码保持通用性,您可以使用额外的@Input() 来表示特殊字词。

在您的应用程序的styles.scss 中,您可以定义CSS 类.special

.special 
  font-weight: bold;

如果您想知道为什么不能使用类似的逻辑将sentence 的内容替换为如下内容:

    this.sentence = this.sentence.replace(new RegExp(`$this.specialWord`, 'g'),
         `<span class="special">$this.specialWord</span>`);

然后,请注意 Angular 将转义 HTML 标签,它们将按原样出现在输出中。所以你会在浏览器中看到类似这样的东西,而不是样式化的 span。

Hello, it's a <span class="special">beautiful</span> day and I am in a very <span class="special">beautiful</span> city

这就是为什么,我不得不求助于操纵 innerHTML 以便在 Angular 将句子渲染到 DOM 后完成替换。

【讨论】:

我认为在使用像 Angular 这样的框架时,以这种方式修改 innerHTML 有点不受欢迎?我弄错了吗? 你的问题也比较奇特,不知道有没有其他方法可以解决。 @snowfrogdev 确实如此,但对于简单的 html 来说基本上没问题。要执行更多操作,您需要使用 sanitizeDom angular.io/api/platform-browser/DomSanitizer 所以我猜这个解决方案在我不想将单词包装在 我想将它包装在我自己的 Angular 组件中的情况下不起作用?【参考方案3】:

你可以试试这个:D

@Component(
  selector: 'app-test',
  template: `
    <p [innerHTML]="stringFormatted()"></p>
  `,
  styles: []
)
export class TestComponent 

  someString = "If you want my body and you think I'm sexy, come on, sugar, tell me so.";

  stringFormatted() 
    return this.someString.replace(/sexy/g, '<b>sexy</b>');
  

【讨论】:

我认为在使用像 Angular 这样的框架时,以这种方式修改 innerHTML 有点不受欢迎?我弄错了吗? 对我来说,这是满足您要求的最简单方法。 真的,我不确定是否有更好的方法。如果字符串是从外部源加载的,你应该通过 DOMsanitizer 传递它,但我认为使用它没有问题。 @snowfrogdev :您可以阅读DOM Sanitization 以确保没有恶意软件被注入。 所以我猜这个解决方案在我不想将单词包装在 我想将它包装在我自己的 Angular 组件中的情况下不起作用?

以上是关于在 Angular 中,我如何动态地将某些单词包装在另一个 html 元素中?的主要内容,如果未能解决你的问题,请参考以下文章

如何包装尚未包装的单词或单词序列?

如何在没有被剪切的单词的情况下逐个字母地将单词实例化

如何动态地将组件作为子组件添加到指令中?

动态地,在运行时,如何在 WPF 中更改文本框中某些单词的颜色?

溢出包装不会破坏动态添加的 div 上的单词

我可以动态地将计算属性插入到 Vue 组件中吗