在不允许 HTML 标签的情况下将 Markdown 转换为 HTML

Convert Markdown to HTML without allowing HTML Tags

我正在尝试构建一个支持 markdown 的 textarea。我已成功将 markdown 转换为 HTML 以显示预览,使用以下管道:

import { Pipe, PipeTransform } from '@angular/core';
import * as marked from 'marked';
import * as DOMPurify from 'dompurify';

@Pipe({ name: 'markdown' })
export class MarkdownPipe implements PipeTransform {

  markdownToSafeHtml(value: string): string {
    const html = marked(value);
    const safeHtml = DOMPurify.sanitize(html);
    return safeHtml;
  }

  transform(str: string): string {
    if (str && str.length > 0) {
      const html = this.markdownToSafeHtml(str);
      return html.toString();
    }

    return str;
  }
}

以及以下 HTML:

<div [innerHTML]="value | markdown">

它正在工作并显示降价设计,但问题是我可以在降价字符串中添加任何 HTML 标签,因为我使用的是 innerHTML div将使用它们,例如在此标签的预览中使用 <h1>hello</h1> 呈现,它应该将其呈现为文本。

  1. 如果没有其他 HTML 标签,我如何转换为 markdown?
  2. 我已经尝试过对HTML字母进行编码(例如&amp;等),问题是在使用code markdown时,转换为:<div>example</div>&lt;div&gt;example&lt;/div&gt;

使用下面的管道终于成功了。

解决方案是创建一个包含 HTML 的元素,并使用 unescapeCodes 函数反转 <code> 元素中的 HTML 转义。

import { Pipe, PipeTransform } from '@angular/core';
import * as marked from 'marked';
import * as DOMPurify from 'dompurify';

@Pipe({ name: 'markdown' })
export class MarkdownPipe implements PipeTransform {
  constructor() {

  }

  private escapeHTML(str: string) {
    return str.replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#039;");
  }

  private unescapeHTML(str: string) {
    return str.replace(/&amp;/g, "&")
      .replace(/&lt;/g, "<")
      .replace(/&gt;/g, ">")
      .replace(/&quot;/g, "\"")
      .replace(/&#039;/g, "'");
  }

  private markdownToSafeHtml(value: string): string {
    const html = marked(value);
    return DOMPurify.sanitize(html);
  }

  private unescapeCodes(value: string) {
    const el = document.createElement("div");
    el.innerHTML = value;
    const codes = el.getElementsByTagName('code');
    for (let i = 0; i < codes.length; i++) {
      codes.item(i).innerText = this.unescapeHTML(codes.item(i).innerText);
    }

    return el.innerHTML.toString();
  }

  transform(str: string): string {
    if (!str || str.length == 0) return str;

    str = this.escapeHTML(str);
    let html = this.markdownToSafeHtml(str);
    html = this.unescapeCodes(html);
    return html;
  }
}