web-dev-qa-db-fra.com

Comment utiliser CKEditor avec React.js de manière à ce que React le reconnaisse?

J'ai essayé d'utiliser composantWillMount et composantDidMount pour initialiser CKEditor dans le contexte de React, mais cela ne semble pas fonctionner, peu importe la combinaison que j'essaie. Quelqu'un at-il trouvé une solution à cela en plus du changement d'éditeur?

12
Slbox

J'ai publié un paquet sur Npm pour utiliser CKEditor avec React. Il ne faut qu'une ligne de code à intégrer à votre projet. 

Lien Github - https://github.com/codeslayer1/react-ckeditor .

Comment utiliser?

  • Installez le paquet en utilisant npm install react-ckeditor-component --save.
  • Ensuite, incluez le composant dans votre application React et transmettez-lui votre contenu et tous les autres accessoires dont vous avez besoin (tous les accessoires répertoriés sur la page Github) - 

<CKEditor activeClass="editor" content={this.state.content} onChange={this.updateContent} />

Le paquet utilise la version par défaut de CKEditor, mais vous pouvez également utiliser une version personnalisée avec l’un des plugins de votre choix. Il comprend également un exemple d'application. J'espère que vous le trouverez utile.

17
codeslayer1

Sage décrit une solution géniale dans sa réponse. Cela m'a sauvé la vie, car je viens tout juste de commencer à utiliser React et j'en avais besoin pour que cela fonctionne. Cependant, j'ai changé la mise en œuvre, en intégrant également les suggestions de Jared (en utilisant componentDidMount). En outre, mon besoin était d'avoir un rappel de changement, comme suit:

Utilisation du composant:

<CKEditor value={this.props.value} onChange={this.onChange}/>

Ajouté ceci à index.html:

<script src="//cdn.ckeditor.com/4.6.1/basic/ckeditor.js"></script>

En utilisant le code de composant suivant:

import React, {Component} from "react";

export default class CKEditor extends Component {
  constructor(props) {
    super(props);
    this.componentDidMount = this.componentDidMount.bind(this);
  }

  render() {
    return (
      <textarea name="editor" cols="100" rows="6" defaultValue={this.props.value}></textarea>
    )
  }

  componentDidMount() {
    let configuration = {
      toolbar: "Basic"
    };
    CKEDITOR.replace("editor", configuration);
    CKEDITOR.instances.editor.on('change', function () {
      let data = CKEDITOR.instances.editor.getData();
      this.props.onChange(data);
    }.bind(this));
  }
}

Encore une fois, tous les crédits à Sage!


Voici une version améliorée de la version de base ci-dessus, qui prend en charge plusieurs instances de CKEditor sur la même page:

import React, {Component} from "react";

export default class CKEditor extends Component {
  constructor(props) {
    super(props);
    this.elementName = "editor_" + this.props.id;
    this.componentDidMount = this.componentDidMount.bind(this);
  }

  render() {
    return (
      <textarea name={this.elementName} defaultValue={this.props.value}></textarea>
    )
  }

  componentDidMount() {
    let configuration = {
      toolbar: "Basic"
    };
    CKEDITOR.replace(this.elementName, configuration);
    CKEDITOR.instances[this.elementName].on("change", function () {
      let data = CKEDITOR.instances[this.elementName].getData();
      this.props.onChange(data);
    }.bind(this));
  }
}

Veuillez noter que cela nécessite également un identifiant unique:

<CKEditor id={...} value={this.props.value} onChange={this.onChange}/>
13
Sander Verhagen

Ceci est pour un composant React qui affiche un P paragraphe de texte. Si l'utilisateur souhaite modifier le texte du paragraphe, il peut cliquer dessus pour attacher une instance de CKEditor. Lorsque l'utilisateur a terminé de modifier le texte dans l'instance de l'éditeur, l'événement "flou" se déclenche, ce qui transfère les données de CKEditor à une propriété state et détruit l'instance de CKEditor. 

import React, {PropTypes, Component} from 'react';

export default class ConditionalWYSIWYG extends Component {
    constructor(props) {
        super(props);
        this.state = {
            field_name:this.props.field_name,
            field_value:this.props.field_value,
            showWYSIWYG:false
        };
        this.beginEdit = this.beginEdit.bind(this);
        this.initEditor = this.initEditor.bind(this);
    }
    render() {
        if ( this.state.showWYSIWYG  ) {
            var field = this.state.field_name;
            this.initEditor(field);
            return (
                <textarea name='editor' cols="100" rows="6" defaultValue={unescape(this.state.field_value)}></textarea>
            )
        } else {
            return (
                <p className='description_field' onClick={this.beginEdit}>{unescape(this.state.field_value)}</p>
            )
        }
    }
    beginEdit() {
        this.setState({showWYSIWYG:true})
    }
    initEditor(field) {
        var self = this;

        function toggle() {
            CKEDITOR.replace("editor", { toolbar: "Basic", width: 870, height: 150 });
            CKEDITOR.instances.editor.on('blur', function() {

                let data = CKEDITOR.instances.editor.getData();
                self.setState({
                    field_value:escape(data),
                    showWYSIWYG:false
                });
                self.value = data;
                CKEDITOR.instances.editor.destroy();
            });
        }
        window.setTimeout(toggle, 100);
    }
}

Le self.value = data me permet de récupérer le texte du composant parent via une simple référence

window.setTimeout(); donne le temps de réaction pour faire ce qu’il fait. Sans ce délai, j'obtiendrais une erreur Cannot read property 'getEditor' of undefined dans la console. 

J'espère que cela t'aides

6
Sage

Il suffit de référencer le ckeditor.js dans index.html et de l’utiliser avec window.CKEDITOR. N'utilisez pas CKEDITOR directement comme le document dans le composant React. 

Il suffit de lire la première ligne de ckeditor.js, vous trouverez ce qu'il en est de définir CKEDITOR.

1
xiongkailing

Merci à Sage, Sander & co. Je voulais juste contribuer à une version pour le mode "intégré" de CKEditor.

Tout d'abord, désactivez le comportement "auto-inline" de CKEditor avec ...

CKEDITOR.disableAutoInline = true

Ensuite, pour le composant réel ...

import React, {Component} from 'react';

export default class CKEditor extends Component {
    constructor(props) {
        super(props);
        this.elementName = "editor_" + this.props.id;
        this.componentDidMount = this.componentDidMount.bind(this);
        this.onInput = this.onInput.bind(this);
    }

    onInput(data) {
        console.log('onInput: ' + data);
    }

    render() {
        return (
            <div 
                contentEditable={true} 
                suppressContentEditableWarning
                className="rte"
                id={this.elementName}> 
                {this.props.value}</div>
        )
    }

    componentDidMount() {
        let configuration = {
            toolbar: "Basic"
        };
        CKEDITOR.inline(this.elementName, configuration);
        CKEDITOR.instances[this.elementName].on("change", function() {
            let data = CKEDITOR.instances[this.elementName].getData();
            this.onInput(data);
        }.bind(this));
    }
}

L'utilisation serait quelque chose comme ceci:

<CKEditor id="102" value="something" onInput={this.onInput} />
0
David Silva