我正在参加「掘金·启航计划」!
在本文中,将向您展示如何使用 Slate-react 中的自定义装饰器自动格式化链接。
Slate-react 简介
Slate 是一个使用 TypeScript 开发的富文本编辑器开发框架,诞生于 2016 年,作者是 Ian Storm Taylor。它吸收了 Quill,Prosemirror,Draft.js 的优点,核心数据模型十分精简,具有高度的可扩展性,最新版本为 v0.83.1。
Slate-react 是一个使 Slate 富文本编辑器适应 React 的库。
在 Slate 中,每段文本都表示为一个节点,该库允许我们通过应用自定义 HTML 和 CSS 来设置节点的样式。
要了解有关 Slate-react 的更多信息,请查看官方文档。
设置编辑器
- 安装
slate、slate-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样式,结果呈现如下:
现在我们已经有了编辑器,让我们开始添加装饰器。
添加自定义装饰器
在 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对象,它是一个包含node和path对象的元素。我们将使用两者来查找节点文本中的任何链接,并将它们的位置作为数据附加到节点。
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} />
此时可以看到,输入链接文本,我们的编辑器可以自动格式化我们添加到文本中的任何链接!
结论
在本文中,我们学习了如何在 Slate-react 中使用装饰器格式化链接。您可以为您的编辑器添加更多花里胡哨,例如在外部链接旁边添加图标等功能。