react-draft-wysiwyg vs draft-js
富文本编辑器选型:核心引擎与成品封装
react-draft-wysiwygdraft-js类似的npm包:

富文本编辑器选型:核心引擎与成品封装

draft-js 是 Facebook 开源的 React 富文本编辑器核心框架,提供了底层的状态管理和渲染机制。react-draft-wysiwyg 则是基于 draft-js 构建的成品组件库,封装了工具栏、样式和常用功能。两者并非直接的竞争关系,而是“底层引擎”与“上层封装”的关系。选择 draft-js 意味着你需要自己搭建编辑器界面;选择 react-draft-wysiwyg 则意味着你直接使用一套现成的界面方案。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
react-draft-wysiwyg288,0846,471299 kB753-MIT
draft-js022,635-9546 年前MIT

富文本编辑器架构:核心引擎 vs 成品封装

在 React 生态中构建富文本编辑器时,draft-jsreact-draft-wysiwyg 是两个经常同时出现的名字。但很多开发者容易混淆它们的定位。简单来说,draft-js 是发动机,而 react-draft-wysiwyg 是组装好的整车。理解这一层关系,对于架构选型至关重要。

🏗️ 核心定位:底层框架 vs UI 封装

draft-js 是一个核心框架。

  • 它只负责管理编辑器状态(EditorState)和内容模型(ContentState)。
  • 它不提供现成的工具栏、按钮或样式,你需要自己写。
  • 适合需要完全控制编辑器行为的场景。
// draft-js: 需要手动搭建编辑器结构
import { Editor, EditorState } from 'draft-js';

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

  return (
    <div className="editor-container">
      {/* 你需要自己写工具栏 */}
      <div className="toolbar">/* 自定义按钮 */</div>
      {/* 核心编辑器区域 */}
      <Editor 
        editorState={editorState} 
        onChange={setEditorState} 
      />
    </div>
  );
}

react-draft-wysiwyg 是一个封装组件。

  • 它基于 draft-js 开发,内置了工具栏、链接弹窗、图片上传等 UI。
  • 你只需要配置参数,不需要写底层渲染逻辑。
  • 适合追求开发效率、需要标准功能的场景。
// react-draft-wysiwyg: 直接使用封装好的组件
import { Editor } from 'react-draft-wysiwyg';

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

  return (
    <Editor 
      editorState={editorState}
      onEditorStateChange={setEditorState}
      toolbar={{ /* 配置工具栏选项 */ }}
      wrapperClassName="demo-wrapper"
      editorClassName="demo-editor"
    />
  );
}

🎨 工具栏定制:从零构建 vs 配置选项

draft-js 要求你手动实现所有交互。

  • 点击加粗按钮时,你需要调用 RichUtils.toggleInlineStyle
  • 你需要自己管理按钮的激活状态(active state)。
  • 灵活性最高,但代码量最大。
// draft-js: 手动处理样式切换
const handleToggle = (style) => {
  onChange(
    RichUtils.toggleInlineStyle(editorState, style)
  );
};

<button 
  onClick={() => handleToggle('BOLD')}
  className={editorState.getCurrentInlineStyle().has('BOLD') ? 'active' : ''}
>
  B
</button>

react-draft-wysiwyg 通过配置对象控制工具栏。

  • 你只需要声明需要哪些按钮(如 bold, italic, link)。
  • 激活状态和交互逻辑由库内部处理。
  • 灵活性受限,但开发速度极快。
// react-draft-wysiwyg: 配置化工具栏
<Editor 
  editorState={editorState}
  onEditorStateChange={setEditorState}
  toolbar={{
    inline: { inDropdown: false },
    options: ['inline', 'blockType', 'list'],
    inline: { options: ['BOLD', 'ITALIC', 'UNDERLINE'] }
  }}
/>

📦 内容状态管理: Immutable 数据流

两者都依赖 draft-js 的核心数据模型,所以在数据处理上是相同的。

  • 都使用 ContentState 来存储文本内容。
  • 都依赖 Immutable.js 数据结构(这是 draft-js 的特点)。
  • 导出 HTML 或 JSON 时,都需要使用转换工具。
// 两者通用:导出 HTML 内容
import { convertToHTML } from 'draft-convert';
import { ContentState } from 'draft-js';

const contentState = editorState.getCurrentContent();
const html = convertToHTML(contentState);
// 结果:'<p>Hello <strong>World</strong></p>'
// 两者通用:从 HTML 导入内容
import { convertFromHTML } from 'draft-convert';
import { ContentState, EditorState } from 'draft-js';

const blocksFromHTML = convertFromHTML(htmlContent);
const state = ContentState.createFromBlockArray(
  blocksFromHTML.contentBlocks,
  blocksFromHTML.entityMap
);
const editorState = EditorState.createWithContent(state);

⚠️ 维护状态与生态风险

这是架构决策中最需要警惕的部分。

draft-js 处于维护模式。

  • Facebook 官方已不再积极开发新功能。
  • 社区普遍认为它是“遗留技术”,虽然稳定但缺乏新特性。
  • 如果开始新项目,建议评估 Slate.js 或 TipTap 等现代替代方案。
// 风险提示:draft-js 依赖 Immutable.js
// 这增加了包体积,且 API 学习曲线较陡
import { Map, List } from 'immutable'; 
// 现代编辑器多已转向普通 JavaScript 对象

react-draft-wysiwyg 依赖上游状态。

  • 它的更新速度受限于 draft-js 的架构。
  • 如果遇到底层 Bug,修复周期可能较长。
  • 适合维护现有项目,新项目需慎重考虑长期维护成本。
// 风险提示:封装库可能滞后于 React 新版本
// 例如 React 18 的并发特性可能未完全适配
import { Editor } from 'react-draft-wysiwyg'; 
// 需测试在 StrictMode 下的行为

🤝 相似之处:共同的技术底座

尽管一个是核心一个是封装,它们共享许多底层特性。

1. 🧱 基于 Block 的内容模型

  • 都将内容视为块(Block)的集合。
  • 段落、列表、图片都是不同类型的 Block。
// 两者通用:获取当前块类型
const selection = editorState.getSelection();
const currentBlock = contentState.getBlockForKey(selection.getStartKey());
const type = currentBlock.getType(); // 例如 'unordered-list-item'

2. 🔌 插件扩展机制

  • 都支持通过插件系统扩展功能。
  • draft-jsdraft-js-plugins 生态。
  • react-draft-wysiwyg 继承了这个能力。
// 两者通用:使用插件创建编辑器状态
import createImagePlugin from 'draft-js-image-plugin';
const imagePlugin = createImagePlugin();
const editorState = EditorState.createEmpty(pluginsDecorator);

3. 📝 自定义渲染器

  • 都允许自定义块组件的渲染方式。
  • 可以通过 blockRendererFn 控制特定块的 UI。
// 两者通用:自定义块渲染
function blockRendererFn(contentBlock) {
  if (contentBlock.getType() === 'atomic') {
    return {
      component: MyAtomicComponent,
      editable: false,
    };
  }
}

📊 总结:核心差异对比

特性draft-jsreact-draft-wysiwyg
定位🧠 核心引擎框架📦 成品 UI 组件库
工具栏🛠️ 需完全手写实现⚙️ 配置化生成
开发成本📈 高(需处理底层逻辑)📉 低(开箱即用)
定制能力🚀 无限定制🔒 受限于封装逻辑
依赖关系💠 无依赖(核心)🔗 依赖 draft-js
维护状态⚠️ 维护模式(更新慢)⚠️ 跟随上游(更新慢)

💡 架构师建议

draft-js 像是一套精密的机械零件 🧩——适合那些需要自己组装引擎、对性能和控制力有极致要求的团队。但你要清楚,这套零件的设计图纸已经几年没有大更新了。

react-draft-wysiwyg 像是一辆组装好的家用车 🚗——适合需要立刻上路、功能标准且不需要改装引擎的团队。它能帮你省下几个月的开发时间,但你要接受它的配置限制。

最终建议:如果是维护旧项目,两者配合依然稳定可靠。如果是全新项目,建议认真评估 Slate.jsTipTap。它们提供了更现代的 API 设计(不依赖 Immutable.js),社区活跃度更高,更适合未来 3-5 年的技术演进。但如果必须在二者中选,追求效率选封装,追求控制选核心。

如何选择: react-draft-wysiwyg vs draft-js

  • react-draft-wysiwyg:

    选择 react-draft-wysiwyg 如果你需要快速上线一个标准的富文本编辑器,且不需要深度定制工具栏逻辑。它适合中小型项目或后台管理系统,能大幅减少样板代码,但需接受其依赖 draft-js 的技术限制及维护现状。

  • draft-js:

    选择 draft-js 如果你的团队需要完全定制编辑器界面,或者现有的封装无法满足特定的业务交互需求。它适合有足够开发资源去维护底层逻辑的大型项目,但要注意其生态更新较慢,适合需要深度控制渲染行为的场景。

react-draft-wysiwyg的README

React Draft Wysiwyg

A Wysiwyg editor built using ReactJS and DraftJS libraries. Demo Page.

Build Status

Features

  • Configurable toolbar with option to add/remove controls.
  • Option to change the order of the controls in the toolbar.
  • Option to add custom controls to the toolbar.
  • Option to change styles and icons in the toolbar.
  • Option to show toolbar only when editor is focused.
  • Support for inline styles: Bold, Italic, Underline, StrikeThrough, Code, Subscript, Superscript.
  • Support for block types: Paragraph, H1 - H6, Blockquote, Code.
  • Support for setting font-size and font-family.
  • Support for ordered / unordered lists and indenting.
  • Support for text-alignment.
  • Support for coloring text or background.
  • Support for adding / editing links
  • Choice of more than 150 emojis.
  • Support for mentions.
  • Support for hashtags.
  • Support for adding / uploading images.
  • Support for aligning images, setting height, width.
  • Support for Embedded links, flexibility to set height and width.
  • Option provided to remove added styling.
  • Option of undo and redo.
  • Configurable behavior for RTL and Spellcheck.
  • Support for placeholder.
  • Support for WAI-ARIA Support attributes
  • Using editor as controlled or un-controlled React component.
  • Support to convert Editor Content to HTML, JSON, Markdown.
  • Support to convert the HTML generated by the editor back to editor content.
  • Support for internationalization.

Installing

The package can be installed from npm react-draft-wysiwyg

$ npm install --save react-draft-wysiwyg draft-js

Getting started

Editor can be used as simple React Component:

import { Editor } from "react-draft-wysiwyg";
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
<Editor
  editorState={editorState}
  toolbarClassName="toolbarClassName"
  wrapperClassName="wrapperClassName"
  editorClassName="editorClassName"
  onEditorStateChange={this.onEditorStateChange}
/>;

Docs

For more documentation check here.

Questions Discussions

For discussions join public channel #rd_wysiwyg in DraftJS Slack Organization.

Fund

You can fund project at Patreon.

Thanks

Original motivation and sponsorship for this work came from iPaoo. I am thankful to them for allowing the Editor to be open-sourced.

License

MIT.