集成 uiw/react-md-editor

在2004年John Gruber发明Markdown之前,WYSIWYG编辑器常用于编辑网站和网络上的内容。然而,Markdown通过提供一种更简单的方式来格式化纯文本文档中的元素,引入了高级内容编辑的新时代。如今,Markdown已成为全球最流行的标记语言之一,使网页作者能够创建需要HTML的文章,而无需编写实际的HTML代码的复杂性。

Markdown因其简单直接的语法而受到欢迎,使其对于熟悉基本文本格式工具的任何人都易于使用。与传统方法相比,它提供了广泛的功能,导致了在需要文本格式化能力的企业Web应用程序中广泛采用Markdown。

在本文中,我们将探讨集成uiw/react-md-editor (opens new window)的过程。

什么是react-md-editor

React markdown编辑器,也被称为uiw/react-md-editor,是由UIW(React UI组件)团队开发的一个简单而强大的React Markdown编辑库。它为在React应用程序中创建和修改Markdown内容提供了无缝的文本编辑体验。

通过uiw/react-md-editor库,用户可以通过用户友好且可定制的编辑器界面轻松地组合和编辑Markdown内容。它配备了各种功能,包括语法高亮显示、用于文本格式化的工具栏选项、实时预览以及将Markdown渲染为HTML的能力。

uiw/react-md-editor库与其他React markdown库的不同之处在于它包含了一个专门的“预览”窗格,使用户能够即时可视化他们的内容。 请注意。在本文中,我们将简单明了地将uiw/react-md-editor库称为“React Markdown编辑器”。

项目设置 #

在本教程中,我们将使用refine创建一个React应用程序,refine是一个专为开发无头企业Web应用程序而设计的React框架。我们将利用refine的预生成页面和内容来演示如何将React Markdown整合到一个与真实应用程序非常相似的应用程序中。

我们将使用npm create refine-app命令来交互式地初始化项目。

由于本教程不需要复杂的项目设置,我们可以选择以下选项,这些选项对于我们的目的来说已经足够了:

✔ 选择一个项目模板 · refine-react✔ 您想为您的项目命名吗?:· refine-markdown✔ 选择要连接的后端服务:· REST API✔ 您想使用哪个UI Framework 完成设置后,导航到项目文件夹并使用以下命令启动你的应用程序:

一旦你执行了这些命令,开发服务器将自动在你默认的 Web 浏览器的一个新标签页中启动应用程序。如果出于任何原因应用程序没有自动打开,你可以手动访问它,方法是导航到 `http://localhost:5173`。

访问该 URL 后,应用程序将显示,并且你应该看到一个与下面图片所示相似的屏幕。

![docker exec](https://refine.ams3.cdn.digitaloceanspaces.com/blog/2023-08-24-react-markdown/project-setup.png)

现在我们的项目已经完全设置好并准备使用,我们可以继续将 React Markdown 编辑器包集成到我们的应用程序中。


## 使用 MDEditor 组件[​](#using-the-mdeditor-component "直接链接到使用 MDEditor 组件")

将 React Markdown 编辑器集成到你的项目中的第一步是在项目中引入 MDEditor 组件。 将包作为依赖项进行安装。要完成此操作,请运行以下命令:

npm i @uiw/react-md-editor


下一步是在项目中需要的位置实现`MDEditor`组件。在我们的示例中,我们将在`create`和`edit`页面中使用该组件,这是我们应用程序的表单所在的位置。

首先,在`create`和`edit`页面中导入`MDEditor`组件,从表单中删除现有的`Textarea`组件,并插入`MDEditor`组件,如下所示:

import MDEditor from "@uiw/react-md-editor"; ...<Form.Item label={translate("blog_posts.fields.content")} name="content" rules={[ { required: true, }, ]}> </Form.Item>; ...


这将在表单上呈现一个具有支持 markdown 编辑和预览窗格的原生`Textarea`元素。

![docker exec](https://refine.ams3.cdn.digitaloceanspaces.com/blog/2023-08-24-react-markdown/using-md-editor-min.gif) 在大多数情况下,使用以下属性将允许您在应用程序中呈现一个完全功能的React Markdown编辑器:

*   `value`:此属性用于指定Markdown内容的初始值或当前值。
*   `onChange`:此属性负责处理对Markdown内容的更改。

在我们的示例应用程序中,您可能会注意到我们并没有使用这些属性,但应用程序的功能仍然有效。这是因为refine中的Ant Design表单组件专门设计用于与React Markdown编辑器包无缝集成。因此,它会自动获取Markdown的值,无需额外努力。

在典型的React应用程序中,有必要创建一个状态来捕获和存储Markdown的值,然后将其分配给Markdown编辑器组件上的`value`和`onChange`属性。这确保了编辑器和Markdown内容之间的正确功能和同步。 然而,该包还提供了几个额外的属性,可以用来定制编辑器的工具栏并引入额外的功能。以下是一些可用属性的列表:

*   commands
*   extraCommands
*   previewOptions
*   enableScroll
*   preview

React Markdown编辑器提供了其他几个属性,超出了上述提到的属性。要探索和了解更多关于这些属性的信息,请参考 [文档](https://uiwjs.github.io/react-md-editor/)。

React Markdown编辑器提供的默认工具栏已经足够全面,可以开始使用。然而,如果您需要进一步定制工具栏以更好地满足您的需求,可以使用 `commands` 和 `extraCommands` 属性。 xtraCommand` props. 这些props允许您根据个人需求实现自定义功能和扩展编辑器的功能。

## commands prop[​](#commands-prop "跳转到commands prop")

`commands` prop允许自定义编辑器工具栏中显示的命令。它接受一个定义要包含在工具栏中的特定命令的对象数组。

当提供`commands`属性时,它会自动用定义的自定义命令替换默认工具栏。例如,如果我们在`MDEditor`组件的commands属性上声明一个空数组,就会覆盖默认的工具栏命令:


工具栏上的每个命令都将被移除。

![docker exec](https://refine.ams3.cdn.digitaloceanspaces.com/blog/2023-08-24-react-markdown/command-prop.png)

要手动向工具栏添加预定义的命令属性,您可以将它们作为对象传递, 在`MDEditor`组件的`commands`属性中,将数组分配给命令数组,如下所示:


这将只在工具栏上呈现`bold`和`italic`命令。

我们还可以通过定义具有特定属性的对象并将其传递给`commands`数组来创建自定义命令。

数组中的每个对象都包含定义命令的各种属性,例如名称、键命令、事件等。以下是一些主要属性:

*   `name`:指定命令的名称。
*   `keyCommand`:定义与命令关联的键命令。
*   `buttonProps`:允许向命令添加辅助功能属性。
*   `Icon`:在工具栏上为命令设置图标。
*   `execute`:为命令分配事件或操作。

例如,如果我们希望在工具栏中添加一个`help`命令,以下代码演示了如何实现: 在这里,我们创建一个`help`对象,并分配之前提到的属性来定义命令。这包括指定`name`、`keyCommand`、`buttonProps`和`icon`。此外,一个事件 以下是Markdown的中文翻译,并删除了一级标题:

t被分配为在单击命令时执行的内容,它会在新窗口中打开refine的文档。

```javascript
execute: () => {  window.open("https://refine.dev/", "_blank");},

然后,我们将其传递给MDEditor组件上的commands数组:

<MDEditor  commands={[commands.bold, commands.italic, help]}  data-color-mode="light"/>

docker exec

extraCommands 属性 #

extraCommands属性与commands属性具有相同的作用。它是一个对象数组,用于定义在工具栏上显示的命令。然而,它专门用于添加额外的命令到工具栏,并且这些命令位于工具栏的右侧。

这表明工具栏上显示的previewfullscreen命令是预定义的额外命令。

我们可以添加自定义的额外命令。 使用与commands属性相同的方法将以下Markdown翻译为中文并删除第一级标题:

<MDEditor commands={[commands.bold, commands.italic, help]} extraCommands={[commands.title1, commands.title2, commands.codePreview, commands.codeEdit]} data-color-mode="light"/>;

此外,您可以选择分配预定义的命令对象或创建自定义命令对象,如下面的文档示例所示:

import React, { useContext } from "react";
import MDEditor, { commands, EditorContext } from "@uiw/react-md-editor";

...

const Button = () => {
  const { preview, dispatch }: { preview?: any; dispatch?: any } = useContext(EditorContext);
  const click = () => {
    dispatch({
      preview: preview === "edit" ? "preview" : "edit",
    });
  };
  if (preview === "edit") {
    return (
      <svg width="12" height="12" viewBox="0 0 520 520" onClick={click} />
    );
  }
  return (
    // 返回其他内容
  );
};
``` 在这个例子中,`EditorContext`被用来调度一个动作,该动作使用条件语句将两个预览功能(`preview`和`edit`)合并为一个单一命令。当点击时,该命令将编辑器的预览状态从`edit`切换到`preview`,反之亦然。

* * *

* * *


## 添加自定义预览[​](#添加自定义预览)

```jsx
const codePreview = () => {
  const click = () => {
    // 点击事件处理逻辑
  };

  return (
    <svg width="12" height="12" viewBox="0 0 520 520" onClick={click} />
  );
};

const codePreview = {
  name: "preview",
  keyCommand: "preview",
  value: "preview",
  icon: <Button />,
};

...

return (
  ...
  <Form.Item
    label={translate("blog_posts.fields.content")}
    name="content"
    rules={[
      {
        required: true,
      },
    ]}
  >
    <MDEditor
      commands={[commands.bold, commands.italic, help]}
      extraCommands={[codePreview]}
      data-color-mode="light"
    />
  </Form.Item>
)
``` 一个Markdown编辑器能够执行复杂的计算编辑任务,包括渲染TeX数学方程和从文本生成图表和流程图。虽然React Markdown编辑器默认不包含这些功能,但它提供了与`kaTeX`和`mermaid preview`等库集成的选项。

要在您的应用程序中将`kaTeX`库与React Markdown编辑器包集成,在终端中打开并执行以下命令:

此命令将安装kaTeX包作为您的项目的依赖项。

同样,您可以按照其[文档](https://uiwjs.github.io/react-md-editor/)中概述的相应步骤将mermaid预览库集成进来。

## KaTeX预览[​](#katex-preview "直达KaTeX预览")

kaTeX是一个专为在Web上渲染TeX数学表达式而设计的JavaScript库。React Markdown编辑器利用kaTeX 作为一个预览数学表达式的插件。

要将其添加到编辑器中,您首先必须将包及其对等样式依赖项导入到您的组件中,我们的情况下是“create”和“edit”文件:

import katex from "katex";import "katex/dist/katex.css";


然后,我们将配置编辑器,通过将`previewOptions`属性分配给`MDEditor`组件,将kaTeX表达式格式化和预览为数学表达式,使用以下代码:

=> { const txt = children[0] || ""; if (inline) { if (typeof txt === "string" && /^\$\$(.*)\$\$/.test(txt)) { const html = katex.renderToString( txt.replace(/^\$\$(.*)\$\$/, "$1"), { throwOnError: false, }, ); return ; 以下的 Markdown 转化为中文并删除一级标题:
return <code>{txt}</code>;
}

const code =
  props.node && props.node.children
    ? getCodeString(props.node.children)
    : txt;

if (
  typeof code === "string" &&
  typeof className === "string" &&
  /^language-katex/.test(className.toLocaleLowerCase())
) {
  const html = katex.renderToString(code, {
    throwOnError: false,
  });
  return (
    <code
      style={{ fontSize: "150%" }}
      dangerouslySetInnerHTML={{ __html: html }}
    />
  );
}

return <code className={String(className)}>{txt}</code>;
},
},
}}/>;

以上代码指定了 code 组件在遇到内联或块级代码元素时的行为。如果代码是内联的且包含 KaTeX 表达式(用 $$ 表示),则使用 KaTeX 库进行渲染。如果代码是块级的并且具有 language-katex 类,则将其渲染为代码块。 现在,如果我们将KaTeX表达式输入到编辑器中,它们将被预览为数学表达式。

docker exec

清理Markdown #

在将Markdown输入解析为HTML元素之前,需要对其进行处理,以便在浏览器中呈现。然而,这个解析过程可能会导致跨站脚本攻击(XSS)的潜在漏洞。

XSS是一种常见的Web应用程序安全漏洞,允许恶意用户将客户端脚本注入到Web页面中,绕过同源策略等访问控制。

为了减轻这个风险,重要的是通过删除任何可能有害的HTML标签和属性来清理Markdown文本。这可以确保用户输入正确格式化,而不会 compromise 缺少应用程序的安全性。

rehype-sanitize插件 #

为了防止恶意脚本进入输入区域并保护我们的应用程序,我们需要对解析后的HTML进行清理,以确保其安全性。这就是rehype-sanitize发挥作用的地方。

rehype-sanitize是React markdown编辑器包使用的安全插件,用于处理编辑器内的清理操作。它提供了一种可靠的方法来清理HTML内容并减轻任何潜在的安全风险。

将rehype-sanitize插件集成到我们的应用程序中是一个简单的过程。我们只需要使用以下命令将包安装为依赖项:

npm install rehype-sanitize

然后,我们在createedit文件中导入rehypeSanitize函数,如下所示:

import rehypeSanitize from "rehype-sanitize";

最后,我们将其作为rehypePlugins属性的值传递给 预览选项属性,如下所示的代码:

<MDEditor  data-color-mode="light"  previewOptions={{    rehypePlugins: [[rehypeSanitize]],  }}/>;

现在,如果您尝试将恶意代码解析到编辑器中,rehype-sanitize插件将在预览内容之前删除该代码。下面的GIF图提供了清晰的演示。

在集成rehype-sanitize之前:

docker exec

在集成rehype-sanitize之后:

docker exec

结论 #

我们已经介绍了如何使用uiw/react-md-editor库将Markdown编辑器集成到React应用程序中的大量内容。然而,还有更多关于Markdown编辑器的探索内容。

要全面了解和实现高级功能,请参考相应的文档和资源。 如果你想了解更多有关React Markdown编辑器的功能,我建议参考官方文档 (opens new window)。查阅文档并探索库的创建者提供的示例对于获得详细指导和发现其他用法选项非常重要。

Live CodeSandbox 示例 #

npm create refine-app@latest -- --example blog-refine-markdown