draftjs, как запустить редактор с контентом

Наткнулся на этот классный текстовый редактор, draft.js от фейсбука. Я пытаюсь следовать примеру в github, но я хочу создать редактор с содержимым вместо пустого редактора.

var EditorState = Draft.EditorState;

var RichEditor = React.createClass({
   getInitialState(){
      return {editorState: EditorState.createWithContent("Hello")}
      //the example use this code to createEmpty editor
     // return ({editorState: EditorState.createEmpty()})
   }
});

запустить его, но я получаю сообщение об ошибке, говорящее, что "Uncaught TypeError: contentState.getBlockMap не является функцией"

10 ответов

Решение

Первый аргумент EditorState.createWithContent - это ContentState, а не строка. Вам необходимо импортировать ContentState

var EditorState = Draft.EditorState;
var ContentState = Draft.ContentState;

Используйте ContentState.createFromText и передайте результат в EditorState.createWithContent.

return {
  editorState: EditorState.createWithContent(ContentState.createFromText('Hello'))
};

Я создал набор пакетов для DraftJS, чтобы помочь с импортом и экспортом контента (HTML/Markdown). Я использую их в своем проекте " Реакция на будущее". Вероятно, вы ищете: draft-js-import-html на npm.

npm install draft-js-import-html

Пример того, как вы можете использовать это:

var stateFromHTML = require('draft-js-import-html').stateFromHTML;
var EditorState = Draft.EditorState;

var RichEditor = React.createClass({
  getInitialState() {
    let contentState = stateFromHTML('<p>Hello</p>');
    return {
      editorState: EditorState.createWithContent(contentState)
    };
  }
});

Модули, которые я опубликовал:

Произошли некоторые изменения API, для ясности в этих примерах используется последний API, который является v0.10.0.

Есть много способов, но в основном у вас есть три варианта, в зависимости от того, хотите ли вы использовать простой текст, стилизованный текст или HTML-разметку для ресурса контента.

Какой простой текст очевиден, но для стилизованного текста вам нужно использовать либо сериализованный объект javasript, либо html-разметку.

Давайте начнем с простого текста:

import {Editor, EditorState} from 'draft-js';

class MyEditor extends Component{

  constructor(props) {
    super(props);

    const plainText = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.';
    const content = ContentState.createFromText(plainText);

    this.state = { editorState: EditorState.createWithContent(content)};

    this.onChange = (editorState) => {
      this.setState({editorState});
    }
  }
  render(){
    return(
      <Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
      />
    )
  }
}

Для импорта стилизованного контента в Draft.js предусмотрены служебные функции convertFromRaw и convertFromHTML.

Функция convertFromRaw принимает необработанный объект JavaScript в качестве параметра. Здесь мы используем JSON-объект JSON в качестве источника контента:

class MyEditor extends Component{

  constructor(props) {
    super(props);

    const rawJsText = `{
      "entityMap": {},
      "blocks": [
        {
          "key": "e4brl",
          "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
          "type": "unstyled",
          "depth": 0,
          "inlineStyleRanges": [
            {
              "offset": 0,
              "length": 11,
              "style": "BOLD"
            },
            {
              "offset": 28,
              "length": 29,
              "style": "BOLD"
            },
            {
              "offset": 12,
              "length": 15,
              "style": "ITALIC"
            },
            {
              "offset": 28,
              "length": 28,
              "style": "ITALIC"
            }
          ],
          "entityRanges": [],
          "data": {}
        },
        {
          "key": "3bflg",
          "text": "Aenean commodo ligula eget dolor.",
          "type": "unstyled",
          "depth": 0,
          "inlineStyleRanges": [],
          "entityRanges": [],
          "data": {}
        }
      ]
    }`;

    const content  = convertFromRaw(JSON.parse(rawJsText));
    this.state = { editorState: EditorState.createWithContent(content)};

    this.onChange = (editorState) => {
      this.setState({editorState});
    }
  }
  render(){
    return(
      <Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
      />
    )
  }
}

Draft.js предоставляет функцию convertToRaw, так что вы можете преобразовать состояние вашего редактора в необработанный объект javascript для длительного хранения.

И, наконец, вот как вы делаете это с HTML-разметкой:

class MyEditor extends Component{

  constructor(props) {
    super(props);

    const html = `<p>Lorem ipsum <b>dolor</b> sit amet, <i>consectetuer adipiscing elit.</i></p>
      <p>Aenean commodo ligula eget dolor. <b><i>Aenean massa.</i></b></p>`;

      const blocksFromHTML = convertFromHTML(html);
      const content = ContentState.createFromBlockArray(
        blocksFromHTML.contentBlocks,
        blocksFromHTML.entityMap
      );

    this.state = { editorState: EditorState.createWithContent(content)};

    this.onChange = (editorState) => {
      this.setState({editorState});
    }
  }
  render(){
    return(
      <Editor
        editorState={this.state.editorState}
        onChange={this.onChange}
      />
    )
  }
}

Ты можешь использовать convertFromHTML импортировать HTML с createWithContent

import { convertFromHTML, ContentState } from 'draft-js'

const html = '<div><p>hello</p></div>'
const blocksFromHTML = convertFromHTML(html)
const content = ContentState.createFromBlockArray(blocksFromHTML)
this.state = { 
  editorState: EditorState.createWithContent(content)
}

Как показано в примере Draft для convertFromHtml. Обратите внимание, что 0.9.1 версия не может импортировать изображения, тогда как 0.10.0 Можно.

В 0.10.0createFromBlockArray изменения в:

const content = ContentState.createFromBlockArray(
  blocksFromHTML.contentBlocks,
  blocksFromHTML.entityMap
)

Когда вам нужно инициировать редактор с простым текстом.

использование EditorState.createWithContent а также ContentState.createFromText методы. Рабочий пример - https://jsfiddle.net/levsha/3m5780jc/

constructor(props) {
  super(props);

  const initialContent = 'Some text';
  const editorState = EditorState.createWithContent(ContentState.createFromText(initialContent));

  this.state = {
    editorState
  };
}

Когда вам нужно запустить редактор с содержимым из строки разметки html.

использование convertFromHTML а также ContentState.createFromBlockArray, Рабочий пример - https://jsfiddle.net/levsha/8aj4hjwh/

constructor(props) {
  super(props);

  const sampleMarkup = `
        <div>
        <h2>Title</h2>
        <i>some text</i>
      </div>
    `;

  const blocksFromHTML = convertFromHTML(sampleMarkup);
  const state = ContentState.createFromBlockArray(
    blocksFromHTML.contentBlocks,
    blocksFromHTML.entityMap
  );

  this.state = {
    editorState: EditorState.createWithContent(state),
  };
}

Если у вас есть массив строк, и вы хотите запустить редактор с некоторыми типами блоков по умолчанию draft.js.

Вы можете создать массив ContentBlocks с конструктором new ContentBlock(...) и передать его ContentState.createFromBlockArray метод. Рабочий пример с unordered-list-item - https://jsfiddle.net/levsha/uy04se6r/

constructor(props) {
  super(props);
  const input = ['foo', 'bar', 'baz'];

  const contentBlocksArray = input.map(word => {
    return new ContentBlock({
      key: genKey(),
      type: 'unordered-list-item',
      characterList: new List(Repeat(CharacterMetadata.create(), word.length)),
      text: word
    });
  });

  this.state = {
    editorState: EditorState.createWithContent(ContentState.createFromBlockArray(contentBlocksArray))
  };
}

Когда вам нужно запустить редактор с контентом из ContentState сырая структура JS.

Если вы ранее сохранили свое состояние контента в сырой структуре JS с convertToRaw(прочтите этот ответ для деталей). Вы можете запустить редактор с convertFromRaw метод. Рабочий пример - https://jsfiddle.net/levsha/tutc419a/

constructor(props) {
  super(props);

  this.state = {
    editorState: EditorState.createWithContent(convertFromRaw(JSON.parse(editorStateAsJSON)))
  };
}

В простой, вы можете установить необработанный содержимое HTML в редакторе из начальной стадии или с использованием setState в любое время, как показано ниже.

editorState: EditorState.createWithContent(ContentState.createFromBlockArray(convertFromHTML('<b>Program</b>')))

Импортируйте необходимые компоненты.

import { EditorState, ContentState, convertFromHTML } from 'draft-js'

Я обнаружил, что это чистый способ работы с богатым функционалом. Вы можете добавить больше плагинов в будущем, экспортировать свой контент как .md и т.д., не меняя структуру вашего компонента.

import Draft from 'draft-js';

import DraftPasteProcessor from 'draft-js/lib/DraftPasteProcessor';
const { EditorState, ContentState } = Draft;
import Editor from 'draft-js-plugins-editor';

import createRichButtonsPlugin from 'draft-js-richbuttons-plugin';
const richButtonsPlugin = createRichButtonsPlugin();

class DescriptionForm extends React.Component {

state = {
  editorState: this._getPlaceholder(),
}

_getPlaceholder() {
  const placeholder = 'Write something here';
  const contentHTML = DraftPasteProcessor.processHTML(placeholder);
  const state = ContentState.createFromBlockArray(contentHTML);
  return Draft.EditorState.createWithContent(state);
}

_onChange(editorState) {
  this.setState({
    editorState,
  });
}

render () {
    let { editorState } = this.state;
    return (
      <div>
          <Editor
            editorState={editorState}
            onChange={this._onChange.bind(this)}
            spellCheck={false}
            plugins={[richButtonsPlugin, videoPlugin]}
          />
      </div>
    );
  }
}

Вы можете установить начальное значение для вашего edtitorState, просто добавив следующий код, если вы хотите установить его в формате HTML

this.state = {
  editorState: EditorState.createWithContent(
    ContentState.createFromBlockArray(
      convertFromHTML('<p>My initial content.</p>')
    )
  ),
}

для Nextjs

      import React, { Component } from 'react';
import { EditorState, convertToRaw, ContentState, convertFromHTML } from 'draft- 
js';
import draftToHtml from 'draftjs-to-html';
import dynamic from 'next/dynamic';
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";

const Editor = dynamic(
() => import('react-draft-wysiwyg').then(mod => mod.Editor),
{ ssr: false }
)

let htmlToDraft = null;
if (typeof window === 'object') {
htmlToDraft = require('html-to-draftjs').default;
}

export default class EditorConvertToHTML extends Component {
constructor(props) {
    super(props);
    this.state = {
        editorState: EditorState.createEmpty(),
        contentState: ""
     }
    }

 componentDidMount() {

    const html = '<p>Hey this <strong>editor</strong> rocks d</p>';
    const contentBlock = htmlToDraft(html);
    console.log(contentBlock)
     if (contentBlock) {
        const contentState = 
        ContentState.createFromBlockArray(contentBlock.contentBlocks);
        const editorState = EditorState.createWithContent(contentState);
        console.log(editorState)
        this.setState(
            {
                editorState: EditorState.createWithContent(
                    ContentState.createFromBlockArray(
                        convertFromHTML(html)
                    )
                )
            }
          )
         }
        } 

     onEditorStateChange = (editorState) => {
     this.setState({
        editorState,
      });
     };

    render() {
    const { editorState } = this.state;
    console.log(this.state.editorState.getCurrentContent())
    return (
        <div>
            <Editor
                editorState={editorState}
                wrapperClassName="demo-wrapper"
                editorClassName="demo-editor"
                onEditorStateChange={this.onEditorStateChange}
            />
            <textarea
                disabled
                value= 
      {draftToHtml(convertToRaw(editorState.getCurrentContent()))}
            />
         </div>
        );
      }
        }

вы можете использовать insertText()

      insertContent(){
    const contentState=editorState.getCurrentState();
    const selection=editorState.getSelection();
    const newContentState=Modifer.insertText(contentState,selection,'hello');
    const nextEditorState=EditorState.push(editorState,newContentState,'insert-character')
    setEditorState(nextEditorState)
}
Другие вопросы по тегам