使用 Draft.js 和 react-draft-wysiwyg 在 React 中构建富文本编辑器

前端开发人员通常使用纯文本输入或 textarea用于捕获小尺寸文本段的元素,例如用户名、地址或城市。 在某些情况下,他们需要让用户在 Web 应用程序中输入带多媒体项目的样式化、格式化文本。 然而,纯文本输入无法满足这些要求,因此开发人员倾向于使用富文本编辑器概念。

富文本编辑器已成为我们与 Web 应用程序交互方式中不可或缺的一部分,尤其是在内容生成方面。 基于 Web 的富文本编辑器通常是 所见即所得 HTML 编辑器,可提供样式和格式化文本段的实时预览。 富文本编辑器使您能够控制文本的外观,并为内容创建者提供一种在任何地方创建和发布 HTML 的强大方法。

在本文中,我们将使用 Draft.js 和 react-draft-wysiwyg 构建一个富文本编辑器并显示我们使用该编辑器创建的文本。

什么是 Draft.js?

Draft.js 是 React 的富文本编辑器框架,如何修复Windows上的硬盘I/O设备错误为开发人员提供 API 来构建自己的富文本编辑器实现。 它提供了一个预先开发的 React 组件,用于生成和呈现富文本。 Draft.js 通过提供声明性 API,支持从简单文本格式到嵌入超链接、图像、提及等媒体项等功能,让开发人员能够为各种用例构建富文本编辑器。

Draft.js 不提供预构建的工具栏元素。 它提供原子富文本编辑器构建块作为框架,因此如果我们需要创建带有工具栏的富文本编辑器,我们必须使用基于 Draft.js 的包装器库或从头开始构建一个。

什么是反应草稿所见即所得?

React -draft-wysiwyg 库是一个使用 React 和 Draft.js 库构建的 WYSIWYG(所见即所得)编辑器。 它具有许多您期望从现代 HTML 编辑器组件中获得的可自定义内置功能,如何从 PC 发布/上传 YouTube Shorts例如文本样式按钮、键盘快捷键支持、嵌入媒体项目、表情符号支持等等。

React-draft-wysiwyg 的优点

功能齐全的软件包

React -draft-wysiwyg 库提供了一个富文本编辑器组件,该组件具有所有常规 WYSIWYG 功能和一些高级功能,包括提及和主题标签支持。 您可以将预构建的编辑器安装到您的应用程序中并拥有您需要的所有功能!

可定制性和灵活性

该库不会通过提供严格的功能集来限制开发人员的功能范围。 它允许开发人员通过各种组件道具自定义工具栏和功能。 您甚至可以轻松添加自定义工具栏项目!

快速设置和可用的集成

React-draft-wysiwyg 库还附带了一个简单的 API、趣知笔记 - 分享有价值的教程!不言自明的组件属性和编写良好的文档。 这使您可以在创纪录的时间内为您的 React 应用程序设置富文本编辑器。 此外,您还可以在富文本编辑器组件中使用 Draft.js 核心 API 和一些流行的 Draft.js 社区库。

开始使用 Draft.js 和react-draft-wysiwyg

本教程假设您具备 React 的应用知识。 此外,请确保 您的计算机上安装了Node.js 、 Yarn 或 npm 。 我们将使用 Create React App 来引导我们的项目。

让我们在您选择的目录中创建我们的项目。 可以在命令行中键入下面突出显示的任何命令来完成您的项目。

恩克斯: npx create-react-app draft-js-example

npm( npm init <initializer>在 npm v6+ 中可用): npm init react-app draft-js-example

纱线( yarn create在 v0.25+ 中可用): yarn create react-app draft-js-example

这些将生成一个具有以下目录结构的新 React 项目:

draft-js-example-|
      |__node_mudles/
      |__public/
      |__src/
      |__.gitignore
      |__pacakge.json
      |__README.md
      |__yarn.lock

导航到项目文件夹的根目录并运行它:

cd draft-js-example
​
npm start
# --- or ---
yarn start

这将以开发模式运行应用程序,您可以使用以下命令在浏览器中查看它 http://localhost:3000/:

安装所需的依赖项

以下命令将 Draft.js 和 react-draft-wysiwyg 包安装到您的 React 项目中:

npm install install draft-js react-draft-wysiwyg
# --- or ---
yarn add draft-js react-draft-wysiwyg

设置编辑器

为了开始,我们需要对 src/App.js文件。 我们将导入 editor组件和样式来自 react-draft-wysiwyg和 EditorState从 draft-js.

这 editor使用默认的 Draft.js 编辑器,不带任何样式。 Draft.js 编辑器被构建为受控的 ContentEditable基于 React 的受控输入 API 的组件。 EditorState提供了一个快照 EditorState。 这包括撤消/重做历史记录、内容和光标。

让我们添加一些代码来显示富文本编辑器。 将以下代码添加到您的 App.js文件:

import React, { useState } from 'react';
import { EditorState } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
​
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import './App.css';
​
function App() {
  const [editorState, setEditorState] = useState(
    () => EditorState.createEmpty(),
  );
​
  return (
    <div className="App">
      <header className="App-header">
        Rich Text Editor Example
      </header>
​
      <Editor
        editorState={editorState}
        onEditorStateChange={setEditorState}
      />
    </div>
  )
}
​
export default App;

我们将从使用创建的空状态开始 createEmpty的方法 EditorState. 这 editor需要 EditorState作为道具。 您会注意到,保存更改并显示更新后,视图看起来不太好:

需要进行一些更改 App.css文件。 将其内容替换为以下内容:

.App-header {
  background-color: #282c34;
  min-height: 5vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
  margin-bottom: 5vh;
  text-align: center;
  padding: 12px;
 }

现在 editor在浏览器视图中的位置很好。 输入一些文本并通过单击 工具栏图标 或按键盘快捷键(例如 Control + B对于粗体文本:

编辑器样式

如果你看看我们上面渲染的编辑器,你会发现很难判断应该在哪里输入文本。 使用样式道具可以使编辑器的不同部分更加明显。 props 可以是应用于特定部分的类,也可以是包含样式的对象:

  • wrapperClassName= "wrapper-class"

  • editorClassName= "editor-class"

  • toolbarClassName= "toolbar-class"

  • wrapperStyle= {<wrapperStyleObject>}

  • editorStyle= {<editorStyleObject>}

  • toolbarStyle= {<toolbarStyleObject>}

添加 className道具 Editor组件和相关样式 App.css如下设置编辑器的样式:

App.js:

<Editor
  editorState={editorState}
  onEditorStateChange={setEditorState}
  wrapperClassName="wrapper-class"
  editorClassName="editor-class"
  toolbarClassName="toolbar-class"
/>

App.css:

.wrapper-class {
  padding: 1rem;
  border: 1px solid #ccc;
}
.editor-class {
  background-color:lightgray;
  padding: 1rem;
  border: 1px solid #ccc;
}
.toolbar-class {
  border: 1px solid #ccc;
}

现在,富文本编辑器应该如下所示:

注意:您可能会注意到一条警告:“ Can’t call setState on a component”在发展模式上。 由于 React-draft-wysiwyg 中存在问题,React 显示此警告消息。 希望库维护者能够尽快发布此问题的修复程序。 现在,您可以 React Strict 模式: 按如下方式禁用本教程的

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
​
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

查看有关此问题的更多详细信息 在 GitHub 上 。

与 EditorState

编辑器可以是 受控组件,也可以是非受控组件 。 受控编辑器是通过使用实现的 EditorState,编辑器的顶级状态对象。

虽然可以使用以下命令创建不受控制的编辑器 EditorState或者 RawDraftContentState,一种流类型,表示内容原始格式的预期结构。 如果我们想创建一个受控编辑器,我们将向其传递以下属性:

  • editorState:以受控方式更新编辑器状态的道具

  • onEditorStateChange:编辑器状态发生更改时调用的函数,该函数采用类型的对象参数 EditorState

添加这些之后,到我们的 editor组件,它看起来像这样:

function App() {
  const [editorState, setEditorState] = useState(
    () => EditorState.createEmpty(),
  );

  return (
    <div className="App">
      <header className="App-header">
        Rich Text Editor Example
      </header>
      <Editor
        editorState={editorState}
        onEditorStateChange={setEditorState}
        wrapperClassName="wrapper-class"
        editorClassName="editor-class"
        toolbarClassName="toolbar-class"
      />
    </div>
  )
}

EditorState还可以用于通过传递创建不受控制的编辑器 defaultEditorState。 这是一个类型的对象 EditorState创建编辑器状态后初始化它:

function App() {
  const [editorState, setEditorState] = useState(
    () => EditorState.createEmpty(),
  );


  return (
    <div className="App">
      <header className="App-header">
        Rich Text Editor Example
      </header>
      <Editor
        defaultEditorState={editorState}
        onEditorStateChange={setEditorState}
        wrapperClassName="wrapper-class"
        editorClassName="editor-class"
        toolbarClassName="toolbar-class"
      />
    </div>
  )
}

实现不受控制的编辑器的另一种方法是使用 RawDraftContentState。 不受控制的编辑器采用以下属性:

  • defaultContentState: 类型的对象 RawDraftContentState创建编辑器状态后对其进行初始化

  • onContentStateChange:编辑器状态发生更改时调用的函数,该函数采用类型的对象参数 RawDraftContentState

使用以下实现的不受控制的编辑器 RawDraftContentState看起来像这样:

import React, { useState } from 'react';
import { ContentState, convertToRaw } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import './App.css';

function App() {
  const _contentState = ContentState.createFromText('Sample content state');
  const raw = convertToRaw(_contentState);  // RawDraftContentState JSON
  const [contentState, setContentState] = useState(raw); // ContentState JSON


  return (
    <div className="App">
      <header className="App-header">
        Rich Text Editor Example
      </header>
      <Editor
        defaultContentState={contentState}
        onContentStateChange={setContentState}
        wrapperClassName="wrapper-class"
        editorClassName="editor-class"
        toolbarClassName="toolbar-class"
      />
    </div>
  )
}

export default App;

渲染后,将显示富文本编辑器,如下所示,并带有预加载的文本:

使用数据转换函数

作为与富文本编辑器交互的用户,您无疑需要保存文本或编辑已保存的文本。 这意味着您应该能够将 ContentState到原始 JavaScript,反之亦然——或者 ContentState到 HTML,反之亦然。 Draft.js 提供了三个函数来帮助您执行此操作:

  • ContentFromRaw:转换原始状态( RawDraftContentState) 到 ContentState。 您可以使用此函数将数据库中保存的原始 JSON 结构加载到富文本编辑器实例

  • ContentToRaw:转换 ContentState至原始状态。 您可以使用此函数将当前的富文本编辑器状态转换为原始 JSON 结构以存储在数据库中

  • ContentFromHTML:将 HTML 片段转换为具有两个键的对象,其中一个键保存一个数组 ContentBlock对象和另一个持有对 entityMap。 然后可以使用该对象从 HTML 文档构造内容状态

对于我们的特定用例,我们希望将编辑器状态转换为 HTML 以便存储和显示。 我们可以使用诸如 Draftjs-to-html 或 Draft-convert 之 类的库来做到这一点。 我们将使用 Draft-convert,因为它比 Draftjs-to-html 有更多功能。

在终端中运行以下命令来安装它:

npm install draft-convert
# --- or ---
yarn add draft-convert

让我们使用 Draft-convert 包从编辑器状态生成 HTML!

为转换后的内容创建预览 EditorState

我们的富文本编辑器已准备好创建一些富文本,但尚未准备好保存或预览我们输入的内容。 您可以使用编辑器和不同的工具栏选项来了解如何创建富文本。 以下是我在此阶段可以使用编辑器执行的不同操作的示例:

下一步是将富文本转换为 HTML。 我们将使用 convertToHTML函数 Draft-convert 来转换它,但首先,我们需要获取编辑器中输入的当前内容。

EditorState提供了一个方法 getCurrentContent返回当前的 ContentState编辑器的,然后我们可以将其转换为 HTML。

我们处理变化的方式 EditorState将不得不改变一点。 将调用一个处理程序来更新 EditorState,该组件存储转换后的 HTML在 JavaScript 变量中。

使用 useEffect钩

让我们添加一个组件,它将采用 editor内容,将其转换为 HTML,并打印原始数据 HTML浏览器控制台上的字符串:

import React, { useState, useEffect } from 'react';
import { EditorState } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import { convertToHTML } from 'draft-convert';

import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import './App.css';

function App() {
  const [editorState, setEditorState] = useState(
    () => EditorState.createEmpty(),
  );
  const [convertedContent, setConvertedContent] = useState(null);

  useEffect(() => {
    let html = convertToHTML(editorState.getCurrentContent());
    setConvertedContent(html);
  }, [editorState]);

  console.log(convertedContent);

  return (
    <div className="App">
      <header className="App-header">
        Rich Text Editor Example
      </header>
      <Editor
        editorState={editorState}
        onEditorStateChange={setEditorState}
        wrapperClassName="wrapper-class"
        editorClassName="editor-class"
        toolbarClassName="toolbar-class"
      />
    </div>
  )
}

export default App;

请注意,某些编辑器格式可能不支持 draft-convert并可能导致错误。

上面的代码使用了 useEffect钩 与 [editorState]要更新的依赖数组 convertedContent状态值。 运行上述代码并输入一些带有样式的文本后,您可以在浏览器控制台上看到当前编辑器状态的原始 HTML 内容,如下所示:

结构之前,编辑器中输入的文本已被转换 现在,在渲染JSX ,我们可以显示它了。 我们将创建一个 div这将显示输入的文本。

因此,要显示文本,我们将使用 dangerouslySetInnerHTML。 你可能会问自己,为什么 dangerously? 通过从代码设置 HTML,您将面临 跨站点脚本 (XSS) 攻击。 这个名字微妙地提醒人们这样做时所涉及的危险。

清理你的 HTML

您必须确保 HTML 的结构正确且经过清理 在将 HTML添加到页面之前, 。 一个简单的方法是使用 dompurify 库。

使用以下命令安装此软件包:

npm install dompurify
# --- or ---
yarn add dompurify

dangerouslySetInnerHTML接收一个带有 a 的对象 __html键(两个下划线)。 这把钥匙将保存已消毒的 HTML。 我们现在可以添加方法来清理 HTML和容纳它的元素。 添加 import DOMPurify from 'dompurify';.

接下来,使用以下函数实现代替现有的 console.log陈述:

function createMarkup(html) {
  return {
    __html: DOMPurify.sanitize(html)
  }
}

现在,渲染经过消毒的 HTML在一个 div如下:

<div className="App">
  <header className="App-header">
    Rich Text Editor Example
  </header>
  <Editor
    editorState={editorState}
    onEditorStateChange={setEditorState}
    wrapperClassName="wrapper-class"
    editorClassName="editor-class"
    toolbarClassName="toolbar-class"
  />
  <div
    className="preview"
    dangerouslySetInnerHTML={createMarkup(convertedContent)}>
  </div>
</div>

这 createMarkup函数接收一个 HTML字符串作为参数并返回一个经过清理的对象 HTML。 这个方法被调用 dangerouslySetInnerHTML与转换为的内容 HTML.

添加样式到 HTML容器

最后,添加一些样式 HTML容器:

.preview {
  padding: 1rem;
  margin-top: 1rem;
}

现在,我们可以在编辑器中输入文本,并看到它显示在富文本编辑器下方,就像我们格式化它一样:

就是这样! 我们完了。 我们构建了一个富文本编辑器,使我们能够以各种方式格式化文本。 最终代码为 App.js文件应该是:

import React, { useState, useEffect } from 'react';
import { EditorState } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import { convertToHTML } from 'draft-convert';
import DOMPurify from 'dompurify';

import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import './App.css';

function App() {
  const [editorState, setEditorState] = useState(
    () => EditorState.createEmpty(),
  );
  const [convertedContent, setConvertedContent] = useState(null);

  useEffect(() => {
    let html = convertToHTML(editorState.getCurrentContent());
    setConvertedContent(html);
  }, [editorState]);

  function createMarkup(html) {
    return {
      __html: DOMPurify.sanitize(html)
    }
  }

  return (
    <div className="App">
      <header className="App-header">
        Rich Text Editor Example
      </header>
      <Editor
        editorState={editorState}
        onEditorStateChange={setEditorState}
        wrapperClassName="wrapper-class"
        editorClassName="editor-class"
        toolbarClassName="toolbar-class"
      />
      <div
        className="preview"
        dangerouslySetInnerHTML={createMarkup(convertedContent)}>
      </div>
    </div>
  )
}

export default App;

自定义富文本编辑器组件

当您使用时,该库默认呈现一般所见即所得功能 Editor无需自定义的组件。 例如,默认情况下,您会获得一个工具栏,其中包含您在富文本编辑器中所期望的功能,例如文本样式和添加嵌入项目。 React-draft-wysiwyg 库非常灵活且功能齐全,它提供了自定义工具栏、行为和启用其他功能的道具。

例如,您可以使用以下命令创建最小工具栏 toolbar道具如下:

<Editor
  editorState={editorState}
  onEditorStateChange={setEditorState}
  wrapperClassName="wrapper-class"
  editorClassName="editor-class"
  toolbarClassName="toolbar-class"
  toolbar={
  
  {
    options: ['inline', 'blockType']
  }}
/>

看下面的预览:

此外,您还可以启用 hashtags和 mentions支持以下道具:

hashtag={
  
  {
  separator: ' ',
  trigger: '#',
}}
mention={
  
  {
  separator: ' ',
  trigger: '@',
  suggestions: [
    { text: 'JavaScript', value: 'javascript', url: 'js' },
    { text: 'Golang', value: 'golang', url: 'go' },
  ],
}}

上述道具可实现以下功能:

中查看所有支持的功能 您可以在官方库文档 。

结论

在本文中,我们着眼于创建一个富文本编辑器,该编辑器已经具有一个工具栏,其中包含多个用于输入和显示文本的选项。 我们仅仅触及了可以使用react-draft-wysiwyg 创建的体验的表面。

中找到其他选项和功能 您可以在react-draft-wysiwyg文档 ,并探索如何构建功能更丰富的编辑器。 如果您希望更多地挑战自己,您可以添加将文本保存到数据库、检索和更新的功能。 本文的代码可以在 GitHub 上找到。 我迫不及待地想看看你建造了什么。

猜你喜欢

转载自blog.csdn.net/weixin_47967031/article/details/132884353
今日推荐