【问题标题】:DraftJs : Custom button to add custom HTML + CSSDraftJs : 添加自定义 HTML + CSS 的自定义按钮
【发布时间】:2021-12-17 18:11:16
【问题描述】:

使用DraftJs 和WYSWYG:我需要在工具栏中创建一个自定义按钮。单击按钮后,一些自定义 HTML(包括 <button>)会添加到内容本身。

我知道如何添加自定义按钮,文档在那里。按钮被添加,onclick 我调用定义的方法insertText。但是使用insertText(draft.js 的 DraftModifier 类中的一种方法)似乎只是将我的 HTML 代码添加为字符串。我应该使用其他方法将自定义 HTML 添加到内容中吗?我想添加真正的 HTML。

这是 TS 声明:

  static insertText(
    contentState: ContentState,
    targetRange: SelectionState,
    text: string,
    inlineStyle?: DraftInlineStyle,
    entityKey?: string
  ): ContentState;

【问题讨论】:

    标签: javascript reactjs typescript draftjs react-draft-wysiwyg


    【解决方案1】:

    您可以使用replaceWithFragment。要构建要插入的片段,首先使用实用程序 convertFromHTML 将字符串转换为 HTML 块

        const htmlContent = convertFromHTML(text);
    

    然后,使用另一个实用程序将内容块数组传递给地图

        const htmlContentMap = BlockMapBuilder.createFromArray(
          htmlContent.contentBlocks
        );
    

    并调用 replaceWithFragment 与调用 insertText 的方式相同,但使用您构建的 HTML 内容的地图

        const newContent = Modifier.replaceWithFragment(
          currentContent,
          currentSelection,
          htmlContentMap
        );
    

    更新

    DraftJS 默认不支持按钮标签,但您可以将其添加为custom block render

    首先,通过将默认支持的标签与按钮标签合并来创建类型映射

    import {
    ...
      DefaultDraftBlockRenderMap,
    ...
    } from "draft-js";
    
    ...
    const mapWithButton = Map({
      button: {
        element: "button"
      }
    }).merge(DefaultDraftBlockRenderMap);
    ...
    

    并将其作为第三个参数传递给convertFromHTML 函数

        const htmlContent = convertFromHTML(
          text,
          undefined,
          mapWithButton
        );
    

    创建自定义块渲染器函数并将其传递给编辑器

    function myBlockRenderer(contentBlock: ContentBlock) {
      const type = contentBlock.getType();
      if (type === "button") {
        return {
          component: () => {
            return (
              <button onClick={() => console.log("doesn't seem to work :(")}>
                {contentBlock.getText()}
              </button>
            );
          },
          editable: false,
        };
      }
    }
    ...
              <Editor
                ...
                customBlockRenderFunc={myBlockRenderer}
              />
    

    它之所以有效是因为它显示了按钮,尽管有时当您插入它时在点之前有文本时,它会将先前的文本与按钮文本合并而不显示按钮。点击不起作用可能是因为this

    如果您的自定义块渲染器需要鼠标交互,通常是 在此期间暂时将您的编辑器设置为 readOnly={true} 是明智的 相互作用。这样,用户不会触发任何选择 与自定义块交互时在编辑器中发生变化。

    https://codesandbox.io/s/insert-html-draftjs-73rmc?file=/src/Editor.tsx

    【讨论】:

    • 谢谢。特别是对于codesandbox,使其更容易。我需要插入一个特定的 HTML,其中包括 &lt;button&gt; 标签。您的代码似乎
    • @TusharShahi 这个按钮有什么作用?
    • @TusharShahi 我用解决方法更新了我的答案,但似乎效果不佳,也许使用 decorators 会是一个更好的选择,但我不确定你会如何将它们混合在里面您正在解析的 HTML。
    【解决方案2】:

    在 react-draft-wysiwyg 的 documentation 中,有一个使用 html 的专用部分,引用如下。基本步骤是:

    1. 使用将 html 转换为 Draft.js 的库ContentBlock。
    2. 使用 ContentBlock 初始化 Draft.js ContentState。
    3. 用 ContentState 初始化 Draft.js ContentEditor
    4. 使用 ContentEditor 对象设置 react-draft-wysiwyg 的 Editor 的 editorState。

    以下是实现这一目标的两个实例:1、2。

    来自 react-draft-wysiwyg 的 documentation 的引用:

    draftjs-to-html 可用于将RawDraftContentState 转换为html。
    html-to-draftjs 提供将react-draft-wysiwyg 生成的HTML 转换回draftJS ContentState 的选项,可用于初始化编辑器.

    import React, { Component } from 'react';
    import { EditorState, convertToRaw, ContentState } from 'draft-js';
    import { Editor } from 'react-draft-wysiwyg';
    import draftToHtml from 'draftjs-to-html';
    import htmlToDraft from 'html-to-draftjs';
     
    class EditorConvertToHTML extends Component {
     constructor(props) {
       super(props);
       const html = '<p>Hey this <strong>editor</strong> rocks ?</p>';
      const contentBlock = htmlToDraft(html);
      if (contentBlock) {
        const contentState = ContentState.createFromBlockArray(contentBlock.contentBlocks);
        const editorState = EditorState.createWithContent(contentState);
        this.state = {
          editorState,
        };
      }
    }
    
    onEditorStateChange: Function = (editorState) => {
      this.setState({
        editorState,
      });
    };
    
    render() {
      const { editorState } = this.state;
      return (
        <div>
          <Editor
            editorState={editorState}
             wrapperClassName="demo-wrapper"
            editorClassName="demo-editor"
            onEditorStateChange={this.onEditorStateChange}
          />
          <textarea
            disabled
            value={draftToHtml(convertToRaw(editorState.getCurrentContent()))}
          />
        </div>
      );
    }
    }
    

    【讨论】:

    • 感谢您的回答。我不认为这完全符合我的预期。我需要能够将自定义 HTML 添加到编辑器中。这包括&lt;button&gt; 标签。这里甚至&lt;a&gt;标签,都在p中。
    • @TusharShahi,对于&lt;a&gt;,您必须使用装饰器,请参阅我链接到的示例。至于&lt;button&gt;,将在检查是否可能之后。
    • @TusharShahi,澄清一下:您想在编辑器的工具栏还是文本区域中添加&lt;button&gt;?
    猜你喜欢
    • 2017-02-08
    • 2017-11-01
    • 2014-11-28
    • 2014-02-15
    • 2022-12-02
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多