Angular 2+ - 我可以制作一个使用路由器导航的指令吗?

Angular 2+ - Can I make a directive that makes use of router navigation?

我正在使用 Angular 5 并试图解决一个问题,我的字符串如下所示:

This is an herbal kind of [tea] found in the...

并输出如下内容:

This is an herbal kind of <a [routerLink]="['/help', 'tea']">Tea</a> found in the...

其中锚标签是可点击的,并流经 Angular 的路由机制,而不需要任何类型的绝对 URL。

我想我也许可以通过指令来做到这一点,但我不确定输出的结果是否会被框架正确评估。

格式对我来说不如一致的路由那么重要,否则我会考虑像 Showdown 这样面向 Markdown 的东西。

按照评论中的建议,我制定了一个指令,该指令解析输入并根据输入向装饰元素添加 DOM 元素,括号中的术语输出范围与触发 [=13 的 onclick 处理程序=]导航。这是一个早期的工作解决方案:

import { Directive, ElementRef, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { MaterialColor } from '../libraries/material-color.enum';
import { Logger } from '../shared/utility/logger';

/**
 * An Angular directive that takes in a string of content and parses out terms inside of brackets, treating them as links to new topics.
 */
@Directive({
  selector: '[emHelpLink]'
})
export class HelpLinkDirective implements OnInit {
  @Input('emHelpLink') public helpContent: string = '';

  constructor(private el: ElementRef, private router: Router) {
    Logger.debug(`Help link directive: ${this.helpContent}`, el);
  }

  /**
   * Responds to the Angular onInit event. It's important to look at helpContent here as it may not be set during construction.
   */
  public ngOnInit(): void {
    this.parseText(this.helpContent);
  }

  /**
   * Parses the input text and adds spans to the native element this directive decorates, replacing bracketed terms with router links.
   * @param {string} input the text to translate
   */
  private parseText(input: string): void {
    if (!input) {
      return;
    }

    // Declare loop variables
    let remaining: string = input;
    let startIndex: number = remaining.indexOf('[');
    let endIndex: number = remaining.indexOf(']');

    /* We're going to loop through and find the first bracketed set of terms, then transform those to links. Items before this will be treated
       as spans, and items afterwards will be re-evaluated for bracketed terms. If no remaining brackets are detected (or no brackets are present)
       the remaining text will be output as a span.
     */
    do {
      startIndex = remaining.indexOf('[');
      endIndex = remaining.indexOf(']');
      if (startIndex >= 0 && endIndex > startIndex) {
        this.addSpanText(remaining.slice(0, startIndex));

        const substring: string = remaining.slice(startIndex + 1, endIndex);
        this.addHelpLink(substring);

        remaining = remaining.slice(endIndex + 1);
      }
    } while (startIndex >= 0 && endIndex > startIndex);

    if (remaining) {
      this.addSpanText(remaining);
    }
  }

  /**
   * Adds a span tag to the document with the specified text
   * @param {string} text the text to include in the span.
   */
  private addSpanText(text: string): void {
    if (!text) {
      return;
    }

    const span: HTMLSpanElement = document.createElement('span');
    span.innerText = text;
    this.el.nativeElement.appendChild(span);
  }

  /**
   * Builds a span tag for the given help text that will navigate to the help topic when clicked. This will be a span tag
   * styled as an anchor tag.
   * @param {string} text the text to display in the link.
   */
  private addHelpLink(text: string): void {
    if (!text) {
      return;
    }

    const link: HTMLElement = document.createElement('span');
    link.style.cursor = 'pointer';
    link.style.color = MaterialColor.blue;
    link.title = `View help on '${text}'`;
    link.innerText = text;
    link.onclick = (): void => this.onLinkClick(text);

    this.el.nativeElement.appendChild(link);
  }

  /**
   * Responds to a help topic link click event by triggering an Angular routing event.
   * @param {string} text the help topic clicked.
   */
  private onLinkClick(text: string): void {
    Logger.debug(`Help topic clicked ${text}`);

    if (!text) {
      return;
    }

    this.router.navigate(['/help', 'topic', text]);
  }
}