Angular 无法在 innerHTML 中呈现 routerLink

Can't render routerLink in innerHTML in Angular

在组件代码中,我有一个名为 taggy 的字段,其中包含一个完整的锚标记。起初,在我的 HTML 中,我将它渲染到屏幕上,这当然没有成功,因为我在逐字版本中只看到了 taggy 的内容。文中字面意思是 hazaa.

谷歌搜索了一下,我发现了我的错误。我应该使用 。它可以工作,但会导致浏览器重新加载,因为我们使用的是 href 而不是 routerLink。当然,我更改了 taggy 的值,所以它显示 routerLink 而不是 href。但是,当我这样做时,它会起作用但不完全是。在我的 HTML 中,我有以下内容。

{{taggy}}
<div [innerHTML]=taggy></div>
<div innerHTML=taggy></div>
其中

None 产生了有效的 link。最接近的是中间那个,因为它创建了一个 div 并且在它里面有一个锚点。但是,锚标记上没有属性,它只包含用户应该阅读的文本。路由信息没了

怎么办?

我找到了 a suggestion but it doesn't feel as a good way to go (even author indicates that it's not the best approach). There's also 但它与我的情况无关,因为我正在将字符串传递给另一个组件。

正如您所发现的,您不能在 Angular 中使用动态模板,因为模板与 javascript 组件捆绑在一起。如果您想了解更多信息,请查看 this issue on github。其结果是:动态模板会破坏 AOT 编译。

您还发现可以将对象的 innerHTML 设置为任意值 HTML,但 routerLink 在该上下文中不起作用。 为什么? 因为 routerlink 是一个 Angular 指令,而不是 HTML 属性。由于我们只是设置 innerHTML,它不是编译模板。

那么,解决方案是什么?让我们回顾一下 routerLink 首先在做什么。事实证明,并不多。看看 the source。具体来说,这是单击具有 routerLink 指令的元素时它正在执行的操作:

@HostListener('click')
onClick(): boolean {
  const extras = {
    skipLocationChange: attrBoolValue(this.skipLocationChange),
    replaceUrl: attrBoolValue(this.replaceUrl),
  };
  this.router.navigateByUrl(this.urlTree, extras);
  return true;
}

它只是使用 HostListener 来监控点击次数,并进行相应的路由。我们可以在我们的组件中做类似的事情。我将其命名为 FooterComponent 因为你提到这是一个带有动态 HTML:

的页脚
import { Component, Input, HostListener } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-footer',
  template: '<div [innerHTML]="footerHtml"></div>'
})
export class FooterComponent {
  @Input() footerHtml: string = "";

  constructor(private router: Router) { }
  // Watch for clicks in our component
  @HostListener("click", ['$event'])
  onClick(event: MouseEvent) {
    // If we don't have an anchor tag, we don't need to do anything.
    if (event.target instanceof HTMLAnchorElement === false) { 
      return;
    }
    // Prevent page from reloading
    event.preventDefault();
    let target = <HTMLAnchorElement>event.target;
    // Navigate to the path in the link
    this.router.navigate([target.pathname]);
  }
}

如您所见,它接收名为 footerHtml 的输入,它是字符串类型。要使用它,我们将在某处添加:

<app-footer [footerHtml]="footerHtml"></app-footer>

其中我们组件中的footerHtml属性定义如下:

footerHtml = '<p>This is the footer with a <a href="/admin">link!</a></p>';

单击元素时,我们会检查以确保用户单击了超链接。如果他们这样做了,我们将使用路由器进行导航并阻止默认行为。这是 working StackBlitz example。希望这对您有所帮助!

根据问题,#Dean 解决方案工作正常,但它不适用于外部 link。也就是说,它只能对 angular 路由路径起作用。以下是我解决内部和外部的解决方案 url/link.

  import { Component, Input, HostListener } from '@angular/core';
  import { Router } from '@angular/router';

  import { Component, Input, HostListener } from '@angular/core';
  import { Router } from '@angular/router';

  @Component({
    selector: 'app-footer',
    template: '<div [innerHTML]="footerHtml"></div>'
  })
  export class FooterComponent {
    footerHtml = '<p>This is the innerHTML content with angular valid path  <a href="/admin">internal link!</a> and external link <a target="_blank" href="https://google.com">external link</a></p>';

    // Watch for clicks in our component
    @HostListener('click', ['$event'])
    onClick(event: MouseEvent) {
    this.routingService.urlLocator(event);
    // Do nothing if no anchor tag.
    if (event.target instanceof HTMLAnchorElement === false) {
      return;
    }

    // Prevent normal html anchor behaviour
    event.preventDefault();

    // Checks if the anchor has a full url name or if target is "_blank"
    // That is, target external url
    if (event.target.target === '_blank') {
      // open it in new window (You can decide to use window.location.href)
      window.open(event.target.href); 
    } else {
      // handle valid angular route path
      const target = <HTMLAnchorElement>event.target;
      this.router.navigate([target.pathname]);
    }
  }
}

如果您不介意为此安装一个库,请查看 ngx-dynamic-hooks。它可以用实际的 Angular 组件替换动态内容字符串中的任何文本 - 包括 link-elements.

有趣的是,我写了一个基于自动替换内部链接的确切想法的示例 [RouterLinks]。看看吧here (or in this Stackblitz).