draftjs как запустить редактор с содержимым

Наткнулся на классный текстовый редактор draft.js от Facebook. Я пытался следовать примеру в 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 не является функцией.


person vdj4y    schedule 09.03.2016    source источник


Ответы (8)


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

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

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

return {
  editorState: EditorState.createWithContent(ContentState.createFromText('Hello'))
};
person Brigand    schedule 09.03.2016

Я создал набор пакетов для DraftJS, которые помогают импортировать и экспортировать контент (HTML/Markdown). Я использую их в своем проекте react-rte. Вероятно, вы ищете: 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)
    };
  }
});

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

person sstur    schedule 15.03.2016
comment
stateFromHTML() очень классный, так как он обрабатывает html-теги, такие как ‹p› и ‹strong›, НО, если я передаю ему строку с тегами ‹sub› или ‹sup›, он их отбрасывает. Любые обходные пути для этого? - person Ben Pritchard; 11.12.2019
comment
К сожалению, у меня нет отличного обходного пути для этого, если только синтаксический анализатор не переписан для обработки большего количества случаев. Честно говоря, весь набор инструментов, который я создал (перечисленный выше), ужасно устарел и больше не поддерживается. - person sstur; 12.12.2019
comment
Здорово иметь. Инициализация редактора с помощью createWithContent не упоминается на странице docs/repo. - person SeanMC; 29.03.2020

Были внесены некоторые изменения в 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 в качестве параметра. Здесь мы используем строковый объект javascript 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}
      />
    )
  }
}
person snnsnn    schedule 02.03.2017
comment
немного в сторону - я не понимаю, как можно использовать объект данных {} при импорте с помощью convertFromRaw() - есть ли примеры вариантов использования? - person David Thorisson; 17.03.2018

Вы можете использовать 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)
}

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

В 0.10.0 createFromBlockArray меняется на:

const content = ContentState.createFromBlockArray(
  blocksFromHTML.contentBlocks,
  blocksFromHTML.entityMap
)
person svnm    schedule 05.12.2016

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

Используйте 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-itemhttps://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)))
  };
}
person Mikhail Shabrikov    schedule 31.10.2017

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

this.state = {
  editorState: EditorState.createWithContent(
    ContentState.createFromBlockArray(
      convertFromHTML('<p>My initial content.</p>')
    )
  ),
}
person Rami Salim    schedule 26.10.2018
comment
откуда вы взяли convertFromHTML? - person Ivan; 01.11.2019

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

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

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

import { EditorState, ContentState, convertFromHTML } from 'draft-js'
person Googlian    schedule 05.09.2020

Я обнаружил, что это чистый способ делать вещи с богатой функциональностью. Вы можете добавить больше плагинов в будущем, экспортировать свой контент как .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>
    );
  }
}
person kaushik94    schedule 14.10.2016
comment
Почему минусы? Мой ответ правильный. Я попросил инициировать с contentState, а не со строкой, как было задано в вопросе. - person kaushik94; 21.06.2019