如何在 Slate-React 中使用装饰器自动格式化链接

1,756 阅读2分钟

Auto Format Links with Decorators in Slate-React.png

我正在参加「掘金·启航计划」!

在本文中,将向您展示如何使用 Slate-react 中的自定义装饰器自动格式化链接。

Slate-react 简介

Slate 是一个使用 TypeScript 开发的富文本编辑器开发框架,诞生于 2016 年,作者是 Ian Storm Taylor。它吸收了 QuillProsemirrorDraft.js 的优点,核心数据模型十分精简,具有高度的可扩展性,最新版本为 v0.83.1

 Slate-react 是一个使 Slate 富文本编辑器适应 React 的库。

在 Slate 中,每段文本都表示为一个节点,该库允许我们通过应用自定义 HTML 和 CSS 来设置节点的样式。

要了解有关 Slate-react 的更多信息,请查看官方文档

设置编辑器

  • 安装slateslate-react
$ yarn add slate slate-react
  • 设置一个基本的编辑器
import { useState } from "react";
import { withReact, Slate, Editable } from "slate-react";
import { createEditor } from "slate";

const initialValue = [
  {
    type: "paragraph",
    children: [{ text: " " }],
  },
];

export const Editor = () => {
  const [editor] = useState(() => withReact(createEditor()));

  return (
    <div>
      <h2>Your custom editor</h2>
      <Slate editor={editor} value={initialValue}>
        <Editable />
      </Slate>
    </div>
  );
};

在这里,我们只是创建了一个编辑器组件Editable,为了方便看到编辑器的位置,添加了css,本文为了简洁省略了css样式,结果呈现如下:

截屏2022-10-12 上午10.04.36.png

现在我们已经有了编辑器,让我们开始添加装饰器。

添加自定义装饰器

在 Slate 中,装饰器是每次编辑器内容更改时运行的自定义函数。它们允许将数据附加到我们的节点,我们稍后可以在渲染它们时使用这些数据。

Editable组件接受一个名为decorate. 这是我们指定自定义装饰器函数的地方。

const myDecorator = ([node, path]) => {
  const nodeText = node.text;

  if (!nodeText) return [];

  const urls = findUrlsInText(nodeText);

  return urls.map(([url, index]) => {
    return {
      anchor: {
        path,
        offset: index,
      },
      focus: {
        path,
        offset: index + url.length,
      },
      decoration: "link",
    };
  });
};

装饰器函数接受一个NodeEntry对象,它是一个包含nodepath对象的元素。我们将使用两者来查找节点文本中的任何链接,并将它们的位置作为数据附加到节点。

findUrlsInText是一个自定义函数,它使用正则表达式来查找文本中所有链接的索引:

export const findUrlsInText = (text) => {
  const urlRegex =
    // eslint-disable-next-line no-useless-escape
    /(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])/gim;

  const matches = text.match(urlRegex);

  return matches ? matches.map((m) => [m.trim(), text.indexOf(m.trim())]) : [];
};

一旦我们有了装饰器功能,就可以将它提供给我们的 Editable组件:

<Editable decorate={myDecorator} />

现在每次编辑器的内容发生变化时,我们的装饰器函数就会运行。每当它找到一个链接时,它都会将它的位置作为数据返回,我们可以在渲染节点时使用它。

添加自定义函数来渲染叶节点

叶子是显示节点内容的 HTML 组件。该Editable组件接收一个props来调用renderLeaf来指定如何渲染我们的叶节点。

renderLeaf函数接收一个包含叶节点数据的对象,数据包含{ attributes, children, leaf }属性。

现在让我们编写一个简单的函数来为编辑器中的节点渲染叶子。如果叶子包含任何链接,我们希望将它们呈现为锚标记。否则我们会将叶子渲染为span元素。

    const Leaf = ({ attributes, children, leaf }) => {
    if (leaf.decoration === "link") {
      children = (
        <a
          style={{ cursor: "pointer" }}
          href={leaf.text}
          onClick={() => {
            window.open(leaf.text, "_blank", "noopener,noreferrer");
          }}
        >
          {children}
        </a>
      );
    }
  
    return <span {...attributes}>{children}</span>;
  };

您可能会注意到我正在为a链接添加href属性和 onClick事件。这是我想出的一种解决方法,因为在 Slate 叶子中呈现的链接由于某种原因不可点击。因此,我们需要添加一个手动点击以确保它在新选项卡中打开 URL,同时添加href属性使其通过 HTML 对链接进行 UI 处理。

最后一步是提供我们的Leaf函数作为我们的道具Editable

<Editable renderLeaf={Leaf} decorate={myDecorator} />

此时可以看到,输入链接文本,我们的编辑器可以自动格式化我们添加到文本中的任何链接!

截屏2022-10-12 上午10.28.51.png

结论

在本文中,我们学习了如何在 Slate-react 中使用装饰器格式化链接。您可以为您的编辑器添加更多花里胡哨,例如在外部链接旁边添加图标等功能。