How can CKEditor be used with React.js in a way that allows React to recognize it?

旧街凉风 提交于 2019-12-17 23:22:29

问题


I've tried using componentWillMount and componentDidMount to initialize CKEditor from within the context of React, but it doesn't seem to work no matter what combination I try. Has anyone found a solution to this besides switching editors?


回答1:


I published a package on Npm for using CKEditor with React. It takes just 1 line of code to integrate in your project.

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

How to Use?

  • Install the package using npm install react-ckeditor-component --save.
  • Then include the component in your React app and pass it your content and any other props that you need(all props listed on Github page) -

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

The package uses the default build of CKEditor but you can use a custom build as well along with any of the plugins you like. It also includes a sample application. Hope you will find it useful.




回答2:


Sage describes an awesome solution in his answer. It was a lifesaver, as I've only just started using React, and I needed it to get this going. I did, however, change the implementation, also incorporating Jared's suggestions (using componentDidMount). Also, my need was to have a change callback, like so:

Usage of the component:

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

Added this to index.html:

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

Using the following component code:

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));
  }
}

Again, all credits to Sage!


The following is an improved version of the basic version above, which supports multiple CKEditor instances on the same 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));
  }
}

Please note that this requires some unique ID to be passed along as well:

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



回答3:


This is for a React component which displays a P paragraph of text. If the user wants to edit the text in the paragraph, they can click it which will then attach a CKEditor instance. When the user is done altering the text in the Editor instance, the "blur" event fires which transfers the CKEditor data to a state property and destroys the CKEditor Instance.

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);
    }
}

The self.value = data allows me to retrieve the text from the parent component via a simple ref

The window.setTimeout(); gives React time to do what it does. Without this delay, I would get an Cannot read property 'getEditor' of undefined error in the console.

Hope this helps




回答4:


Just refer the ckeditor.js in index.html, and use it with window.CKEDITOR. Don't use CKEDITOR straight like the document in React component.

Just read the first-line of ckeditor.js, you will find what about define of CKEDITOR.




回答5:


Thanks to Sage, Sander & co. I just wanted to contribute a version for the "inline" mode of CKEditor.

First, disable CKEditor's "auto-inline" behavior with...

CKEDITOR.disableAutoInline = true

Then, for the actual component...

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));
    }
}

Usage would be something like this:

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


来源:https://stackoverflow.com/questions/36535234/how-can-ckeditor-be-used-with-react-js-in-a-way-that-allows-react-to-recognize-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!