Angular/Typescript 带有 routerLink 的文本

Angular/Typescript Text with routerLink

更新问题更清晰

需要在 Angular HTML 中将一些文本和链接显示为内部 HTML(来自 service/DB 的数据),当用户点击时,它应该转到 Typescript 并以编程方式导航 router.navigate

此外,如何从 @ViewChild/ElementRef

添加 DomSanitizer

在下面的代码中添加了所有示例

Here is the updated stackblitz code

如截图所示 angular.io 一些文本和一些链接

你有一个 css 问题。

  1. <a href="something"></a> 看起来像 link
  2. <a [routerLink]="something"></a> 看起来像 link,因为如果你检查 HTML 它实际上会添加 href 属性 因为 routerLink
  3. <a (click)="goTo()"></a> 看起来不像 link,因为没有 href

Chrome 和 Safari 默认用户代理 css 不会在没有 href 的情况下设置 <a> 样式(尚未确认 Firefox,但我确信它可能)。 bootstrap.

等框架也是如此

更新了 stackblitz CSS 移至全局,而不是 app.css https://stackblitz.com/edit/angular-ivy-kkgmkc?embed=1&file=src/styles.css

这会将所有 link 样式设置为默认蓝色,或者 -webkit-link(如果该浏览器支持)。如果你想让它在整个应用程序中工作,它应该在你的 global.css 文件中。

a {
  color: rgb(0, 0, 238);
  color: -webkit-link;
  cursor: pointer;
  text-decoration: underline;
}

抱歉,我没有意识到你回答了我的评论。 Angular 路由不是次要的,如果您不使用 Angular 模块,您最终只会得到一个 HTML/CSS/Typescript 应用程序。你至少需要 Angular 的 RouterModule 才能使用路由,因此,用 DOM.

做它应该做的事情

第一个:

  • 您没有导入 RouterModule

    解决方案:

    imports: [ 
      BrowserModule, 
      FormsModule, 
      RouterModule.forRoot([])  // this one
    ]
    

第二个:

  • 无法通过内部绑定Angular事件HTML 属性

    修复:

利用 @ViewChild 指令更改 innerHTML 属性 并手动绑定到 click 事件,因此将 app.component.html

<div id="box" [innerHTML]="shouldbedivcontent" ></div>

<div #box id="box"></div>

现在,在您的 app.component.ts 中添加一个 属性 来保存对该“框”元素的引用,以便您稍后可以对 dom 与它:

  @ViewChild('box')  container: ElementRef;

实现 AfterViewInit,那个钩子是你可以实际处理你的容器的地方,如果你尝试在 OnInit 中使用它,你会得到未定义的,因为那个组件的 html 不在 dom还没有。

export class AppComponent  implements AfterViewInit {

ngAfterViewInit() {
    this.container.nativeElement.innerHTML = this.shouldbedivcontent;
    this.container.nativeElement.addEventListener('click', 
      () => this.goto('bar')
    );
}

更改 shouldbedivcontent 属性 来自:

'1) this is a click 
 <a (click)="goto("bar")">Click</a><br> 
 2)this is with routerlink 
 <a routerLink="" (click)="goto("bar")">Click</a><br> 
 3)This only works with href 
 <a href="goto/bar" title="bar">bar</a>&nbsp; and test'

'1) this is a click 
 <a id="link_1">Click</a><br> 
 2)this is with routerlink 
 <a [routerLink]="" (click)="goto(\'bar\')">Click</a><br> 
 3)This only works with href 
 <a href="goto/bar" title="bar">bar</a>&nbsp; and test'

即便如此,除非您自己应用一些样式,否则您仍然无法获得默认的锚点样式。

第三

您没有HTML消毒,这可能很危险。 read more here

我的建议:

对于您来说似乎有很多事情要做,对于与您一起工作的其他人来说似乎有很多事情要阅读,而您可以像下面的示例一样轻松地做到这一点!

将您的 html 移动到您的 app.component.html:

<div id="box">
  1) this is a click 
  <a (click)="goto('bar')">Click</a><br> 
  2)this is with routerlink 
  <a routerLink="" (click)="goto('bar')">Click</a><br> 
  3)This only works with href 
  <a href="goto/bar" title="bar">bar</a>&nbsp; and test
</div>

<p>Below is actual content</p>

你会注意到现在一切正常,除了没有 routerLink 或 href 的锚点,因为那不是 link。

编辑:

看看新的 stackblitz,我建议改变方法,绑定到 innerHTML 在处理纯文本甚至一些简单的 html 时是可以的,但不是绑定事件的好选择或路由逻辑。

Angular 的 Renderer2 提供了一组动态添加元素到 DOM 的方法。有了 table,你只需要一点点努力就可以把你从后端得到的那个简单的 html 变成类似的东西(将这个 属性 粘贴到你的代码中来测试它以及下面提供的其余代码):

public jsonHTML = [
  {
    tagName: '',
    text: 'some text with click ',
    attributes: {
    }
  },
  {
    tagName: 'a',
    text: 'bar',
    attributes: {
      value: 'bar' // goto parameter
    }
  },
  {
    tagName: '',
    text: ' some more text with click ',
    attributes: {
    }
  },
  {
    tagName: 'a',
    text: 'foo',
    attributes: {
      value: 'foo' // goto parameter
    }
  }
]

有了它之后,动态创建所有这些元素就容易多了:

这是您 Q1 中的代码:

private r2: Renderer2

注入 Renderer2

并将AfterViewInit hook中的Q1相关代码替换为:

const parent = this.r2.createElement('div');  // container div to our stuff

this.jsonHTML.forEach((element) => {
  const attributes = Object.keys(element.attributes);
  const el = element.tagName && this.r2.createElement(element.tagName);
  const text = this.r2.createText(element.text);

  if (!el) {  // when there's no tag to create we just create text directly into the div.
    this.r2.appendChild(
      parent,
      text
    );
  } else { // otherwise we create it inside <a></a>
    this.r2.appendChild(
      el,
      text
    );

    this.r2.appendChild(
      parent,
      el
    );
  }
  
  if (attributes.length > 0) {
    attributes.forEach((name) => {
      if (el) {
        this.r2.setAttribute(el, name, element.attributes[name]); // just the value attribute for now

       if (name === 'value') { 
          this.r2.listen(el, 'click', () => {
            this.goto(element.attributes[name]); // event binding with property "value" as parameter to navigate to
          })
        }
      } else {
        throw new Error('no html tag specified as element...');
      }
    })
  }
})

this.r2.appendChild(this.container.nativeElement, parent); // div added to the DOM

不需要 html 消毒剂,也不需要使用 routerLink,只需注入 Router 并导航到您想要的路线!对代码进行改进使其满足您的需求,它至少应该是一个好的起点

祝你好运!

这非常适合我 :D

 @Directive({
  selector: "[linkify]",
})

// * Apply Angular Routing behavior, PreventDefault behavior
export class CustomLinkDirective {
  @Input()
  appStyle: boolean = true;
  constructor(
    private router: Router,
    private ref: ElementRef,
    @Inject(PLATFORM_ID) private platformId: Object
  ) {}

  @HostListener("click", ["$event"])
  onClick(e: any) {
    e.preventDefault();
    const href = e.target.getAttribute("href");
    href && this.router.navigate([href]);
  }

  ngAfterViewInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.ref.nativeElement.querySelectorAll("a").forEach((a: HTMLElement) => {
        const href = a.getAttribute("href");
        href &&
          this.appStyle &&
          a.classList.add("text-indigo-600", "hover:text-indigo-500");
      });
    }
  }
}

我如何使用它

 <p linkify
     class="mt-3 text-lg text-gray-500 include-link"
     [innerHtml]="apiSectionText"
   ></p> 

result