【问题标题】:In Angular how do I dynamically wrap certain words in another html element?在 Angular 中,我如何动态地将某些单词包装在另一个 html 元素中?
【发布时间】: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) 事件处理程序,并查看它是否是您包装它的 标记之一,然后执行一些操作。

标签: html angular components angular-components


【解决方案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 组件中的情况下不起作用?
    猜你喜欢
    • 2014-09-07
    • 2016-11-11
    • 2013-05-17
    • 2016-04-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 2023-03-29
    相关资源
    最近更新 更多