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

In Angular how do I dynamically wrap certain words in another html element?

我有这个简单的 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 元素,例如 <b>。所以在这个例子中它会生成类似的东西:

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

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

你可以试试这个: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>');
  }
}

您可以使用类似下面的内容 - 其中在呈现主句后,您可以用 span 元素替换特殊词并应用 CSS class,比如 .special到那个跨度标签。

从“@angular/core”导入{组件、输入、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 class .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 之后完成替换。

此解决方案避免使用 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');
  }
}