React中使用富文本编辑器react-draft-wysiwyg

在React中用react-draft-wysiwyg:// react-draft-wysiwyg begin

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';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
// react-draft-wysiwyg end
state = {
        showRichText: false, // react-draft-wysiwyg
        editorContent: '', // react-draft-wysiwyg
        editorState: '', // react-draft-wysiwyg
    };
点击并拖拽以移动
/**
     *
     * @react-draft-wysiwyg begin
     */
    handleClearContent = () => {
        this.setState({
            editorState: ''
        })
    }

    handleGetText = () => {
        this.setState({
            showRichText: true
        })
    }

    onEditorChange = (editorContent) => {
        this.setState({
            editorContent,
        });
    };

    onEditorStateChange = (editorState) => {
        this.setState({
            editorState
        });
    };
    // @react-draft-wysiwyg end
提交时将富文本转换为含html的文本: 
addModalHandleOk = e => {
        const _this = this;
        this.addModalFormRef.current.validateFields()
            .then(values => {
                console.log(this.state.editorContent);
                const params = {
                    title: values.title,
                    content: draftToHtml(convertToRaw(this.state.editorState.getCurrentContent()))
                };

                axios.post(`http://localhost:5555/api/add_blog`, qs.stringify(params)).then((resp) => {
                    if (resp.ret) {
                        console.log(resp.msg);
                    } else {
                        this.addModalFormRef.current.resetFields();
                        this.setState({
                            addModalVisible: false
                        });
                        this.getData(1, 5);
                    }
                }, (err) => {
                    console.log(err);
                });
            })
            .catch(info => {
                console.log('Validate Failed:', info);
            });
    }
获取时的文本含有html标签,所以在Modal中用“<div dangerouslySetInnerHTML={{__html: this.state.blogDetail}} style={{height: 300, overflow: 'auto'}}/>”转换成html标签。
/**
     * 显示blog Modal
     */
    handleShowDetailBlog = (id) => {
        axios.get(`http://localhost:5555/api/get_blog_detail?id=${id}`, {}).then((resp) => {

            if (resp.data.ret) {
                this.setState({
                    showBlogModalVisible: true,
                    blogDetail: resp.data.content
                })
            } else {

            }
        }, (err) => {
            console.log(err);
        });
    }
<Modal
                    title="创建"
                    visible={this.state.addModalVisible}
                    width={660}
                    onOk={this.addModalHandleOk}
                    onCancel={this.addModalHandCancel}
                    okText="确认"
                    cancelText="取消"
                    maskClosable={false}
                    destroyOnClose={true}
                >
                    <Form {...layout} ref={this.addModalFormRef} name="control-ref" preserve={false}>
                        <Form.Item label="标题" style={{ marginBottom: 0 }}>
                            <Form.Item
                                name="title"
                                style={{ display: 'inline-block',  'calc(100% - 8px)', marginRight: 15 }}
                                rules={[
                                    {
                                        required: true,
                                        message: "标题不能为空"
                                    }
                                ]}
                            >
                                <Input />
                            </Form.Item>
                        </Form.Item>
                        <Form.Item label="内容" style={{ marginBottom: 0 }}>
                            <Form.Item
                                name="content"
                                style={{ display: 'inline-block',  'calc(100% - 8px)' }}
                                rules={[
                                    {
                                        required: true,
                                        message: "内容不能为空"
                                    }
                                ]}
                            >
                                <Editor
                                    editorState={this.state.editorState}
                                    wrapperClassName="demo-wrapper"
                                    editorClassName="demo-editor"
                                    onEditorStateChange={this.onEditorStateChange}
                                />
                                {/* <TextArea rows={4} /> */}
                            </Form.Item>
                        </Form.Item>
                    </Form>
                </Modal>
<Modal
                    title="详情"
                    visible={this.state.showBlogModalVisible}
                    width={660}
                    onOk={this.handleShowBlogModalHandleOk}
                    onCancel={this.handleShowBlogModalHandleCancel}
                    okText="确定"
                    cancelText="取消"
                    maskClosable={false}
                    destroyOnClose={true}
                    footer={null}
                >

                    <div dangerouslySetInnerHTML={{__html: this.state.blogDetail}} style={{height: 300, overflow: 'auto'}}/>

                </Modal>

完整代码:

import React, { Component } from 'react'
import { Table, Pagination, Card, Modal, Button, Form, Input, InputNumber, Select, Checkbox, Radio, notification } from 'antd'
import ReactEcharts from 'echarts-for-react'
import axios from 'axios'
import qs from 'qs'
import { PlusOutlined, MinusOutlined } from '@ant-design/icons';

// react-draft-wysiwyg begin
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';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
// react-draft-wysiwyg end

const { Option } = Select;
const { TextArea } = Input;

const layout = {
    labelCol: {
        span: 3,
    },
    wrapperCol: {
        span: 19,
    }
};

export default class Home extends Component {
    state = {
        showRichText: false, // react-draft-wysiwyg
        editorContent: '', // react-draft-wysiwyg
        editorState: '', // react-draft-wysiwyg
        chartData: [
            ['2019-10-10', 200],
            ['2019-10-11', 400],
            ['2019-10-12', 650],
            ['2019-10-13', 500],
            ['2019-10-14', 250],
            ['2019-10-15', 300],
            ['2019-10-16', 450],
            ['2019-10-17', 300],
            ['2019-10-18', 200]
        ],
        selectedRowKeys: [], // 表格选择项Keys
        selectedRows: [], // 表格选择项Rows
        tableData: [],
        total: 0, // for Pagination
        columns: [
            {
                title: 'ID',
                dataIndex: 'id',
                 30,
            },
            {
                title: '标题',
                dataIndex: 'title',
                 500,
                render: (text, record) => <a href="javascript: void(0)" target="_self" onClick={() => this.handleShowDetailBlog(record.id)}>{text}</a>
            },
            {
                title: '内容',
                dataIndex: 'content'
            },
        ],
        addModalVisible: false,
        showBlogModalVisible: false,
        blogDetail: ''
    };

    /**
     *
     * @react-draft-wysiwyg begin
     */
    handleClearContent = () => {
        this.setState({
            editorState: ''
        })
    }

    handleGetText = () => {
        this.setState({
            showRichText: true
        })
    }

    onEditorChange = (editorContent) => {
        this.setState({
            editorContent,
        });
    };

    onEditorStateChange = (editorState) => {
        this.setState({
            editorState
        });
    };
    // @react-draft-wysiwyg end

    getSalesVolumeChartData = (chartData) => {
        return {
            grid: {
                left: '3%',
                right: '3%',
                bottom: '3%',
                top: '3%',
                containLabel: true
            },
            xAxis: {
                type: 'category',
                boundaryGap: false
            },
            yAxis: {
                type: 'value',
                boundaryGap: [0, '30%']
            },
            visualMap: {
                type: 'piecewise',
                show: false,
                dimension: 0,
                seriesIndex: 0,
                pieces: [{
                    gt: 1,
                    lt: 3,
                    color: 'rgba(0, 180, 0, 0.5)'
                }, {
                    gt: 5,
                    lt: 7,
                    color: 'rgba(0, 180, 0, 0.5)'
                }]
            },
            series: [
                {
                    type: 'line',
                    smooth: 0.6,
                    symbol: 'none',
                    lineStyle: {
                        color: 'green',
                         5
                    },
                    markLine: {
                        symbol: ['none', 'none'],
                        label: { show: false },
                        data: [
                            { xAxis: 1 },
                            { xAxis: 3 },
                            { xAxis: 5 },
                            { xAxis: 7 }
                        ]
                    },
                    areaStyle: {},
                    data: chartData
                }
            ]
        };
    }

    onTableSelectChange = (selectedRowKeys, selectedRows) => {
        console.log('selectedRowKeys changed: ', selectedRowKeys);
        console.log('selectedRows changed: ', selectedRows);
        this.setState({ selectedRowKeys, selectedRows });
    };

    onSelectChange = selectedRowKeys => {
        console.log('selectedRowKeys changed: ', selectedRowKeys);
        this.setState({ selectedRowKeys });
    };

    /**
     * 表格
     */

    // 获取表格数据
    getData(pageNumber, pageSize) {
        axios.get(`http://localhost:5555/api/blog_list/?pageSize=${pageSize}&pageNumber=${pageNumber}&sortName=id&sortOrder=desc&_=1595230808893`).then((resp) => {
            let ajaxData = [];
            for (let i = 0; i < resp.data.rows.length; i++) {
                ajaxData.push({
                    key: resp.data.rows[i].id,
                    id: resp.data.rows[i].id,
                    title: resp.data.rows[i].title,
                    content: resp.data.rows[i].content,
                });
            }

            this.setState({
                tableData: ajaxData,
                total: resp.data.total
            })

        }, (err) => {
            console.log(err);
        });
    }

    onChange = (pageNumber, pageSize) => {
        this.pageNum = pageNumber;
        this.getData(pageNumber, pageSize);
    };

    /**
     * 添加modal
     */

    // for modal
    showAddModal = () => {
        this.setState({
            addModalVisible: true
        })
    }

    addModalHandleOk = e => {
        const _this = this;
        this.addModalFormRef.current.validateFields()
            .then(values => {
                console.log(this.state.editorContent);
                const params = {
                    title: values.title,
                    content: draftToHtml(convertToRaw(this.state.editorState.getCurrentContent()))
                };

                axios.post(`http://localhost:5555/api/add_blog`, qs.stringify(params)).then((resp) => {
                    if (resp.ret) {
                        console.log(resp.msg);
                    } else {
                        this.addModalFormRef.current.resetFields();
                        this.setState({
                            addModalVisible: false
                        });
                        this.getData(1, 5);
                    }
                }, (err) => {
                    console.log(err);
                });
            })
            .catch(info => {
                console.log('Validate Failed:', info);
            });
    }

    addModalHandCancel = e => {
        this.addModalFormRef.current.resetFields();
        this.setState({
            addModalVisible: false
        })
    }

    /**
     * 删除blog
     */
    onDeleteAdministrators = () => {
        let len = this.state.selectedRowKeys.length;

        if (len === 0) {
            notification['error']({
                message: '错误提示',
                description: '请选择要删除的文章!',
            })
        } else {
            const params = {
                idArr: JSON.stringify(this.state.selectedRowKeys)
            }

            const _this = this;

            axios.post(`http://localhost:5555/api/delete_blogs`, qs.stringify(params)).then((resp) => {
                if (resp.data.ret) {
                    notification['success']({
                        message: '成功提示',
                        description: resp.data.msg,
                    })
                    _this.getData(0, 5);
                } else {
                    notification['error']({
                        message: '错误提示',
                        description: resp.data.msg,
                    })
                }
            }, (err) => {
                notification['error']({
                    message: '错误提示',
                    description: '网络错误,删除失败!'
                })
            });
        }
    }

    // 表单相关
    addModalFormRef = React.createRef(); // 定义一个表单

    /**
     * 显示blog Modal
     */
    handleShowDetailBlog = (id) => {
        axios.get(`http://localhost:5555/api/get_blog_detail?id=${id}`, {}).then((resp) => {
            const contentBlock = htmlToDraft(resp.data.content);
            const contentState = ContentState.createFromBlockArray(contentBlock.contentBlocks);
            const editorState = EditorState.createWithContent(contentState);

            console.log("contentState:");
            console.log(contentState);

            if (resp.data.ret) {
                this.setState({
                    showBlogModalVisible: true,
                    blogDetail: resp.data.content
                })
            } else {

            }
        }, (err) => {
            console.log(err);
        });
    }

    handleShowBlogModalHandleOk = () => {
        this.setState({
            showBlogModalVisible: false
        })
    }

    handleShowBlogModalHandleCancel = () => {
        this.setState({
            showBlogModalVisible: false
        })
    }

    /**
     * 钩子函数
     */
    componentDidMount() {
        this.getData(1, 5);

        setInterval(() => {
            let chartData1 = Math.ceil(Math.random() * 100);
            let chartData2 = Math.ceil(Math.random() * 100);
            let chartData3 = Math.ceil(Math.random() * 100);
            let chartData4 = Math.ceil(Math.random() * 100);
            let chartData5 = Math.ceil(Math.random() * 100);
            let chartData6 = Math.ceil(Math.random() * 100);
            let chartData7 = Math.ceil(Math.random() * 100);
            let chartData8 = Math.ceil(Math.random() * 100);
            let chartData9 = Math.ceil(Math.random() * 100);
            let chartData = [
                ['2019-10-10', chartData1],
                ['2019-10-11', chartData2],
                ['2019-10-12', chartData3],
                ['2019-10-13', chartData4],
                ['2019-10-14', chartData5],
                ['2019-10-15', chartData6],
                ['2019-10-16', chartData7],
                ['2019-10-17', chartData8],
                ['2019-10-18', chartData9]
            ];

            this.setState({ chartData });
        }, 1000)
    }

    render() {
        // 控制表格选择
        const rowSelection = {
            selectedRowKeys: this.state.selectedRowKeys,
            onChange: this.onTableSelectChange
        };

        return (<>
            <Card
                title="Smoothed Line Chart"
            >
                <ReactEcharts option={this.getSalesVolumeChartData(this.state.chartData)}></ReactEcharts>
            </Card>

            <div style={{ height: 15 }}></div>

            <Card title="博客列表" extra={<span><Button type="primary" ghost size="small" icon={<PlusOutlined />} style={{ marginRight: 15 }} onClick={this.showAddModal}>添加</Button><Button type="primary" ghost size="small" icon={<MinusOutlined />} onClick={() => {this.onDeleteAdministrators()} }>删除</Button></span>} style={{  '100%' }}>
                <Table
                    onRow={record => {
                        return {
                            onClick: event => { console.log(record) }, // 点击行
                            onDoubleClick: event => { },
                            onContextMenu: event => { },
                            onMouseEnter: event => { }, // 鼠标移入行
                            onMouseLeave: event => { },
                        };
                    }}
                    rowSelection={rowSelection}
                    columns={this.state.columns}
                    dataSource={this.state.tableData}
                    pagination={{
                        current: this.pageNum,
                        total: this.state.total,
                        pageSizeOptions: [5, 10, 20, 50, 100],
                        defaultPageSize: 5,
                        showSizeChanger: true,
                        showQuickJumper: true,
                        showTotal: (total, range) => `共 ${total} 条`,
                        onChange: this.onChange
                    }}
                    bordered
                >
                </Table>

                <Modal
                    title="创建"
                    visible={this.state.addModalVisible}
                    width={660}
                    onOk={this.addModalHandleOk}
                    onCancel={this.addModalHandCancel}
                    okText="确认"
                    cancelText="取消"
                    maskClosable={false}
                    destroyOnClose={true}
                >
                    <Form {...layout} ref={this.addModalFormRef} name="control-ref" preserve={false}>
                        <Form.Item label="标题" style={{ marginBottom: 0 }}>
                            <Form.Item
                                name="title"
                                style={{ display: 'inline-block',  'calc(100% - 8px)', marginRight: 15 }}
                                rules={[
                                    {
                                        required: true,
                                        message: "标题不能为空"
                                    }
                                ]}
                            >
                                <Input />
                            </Form.Item>
                        </Form.Item>
                        <Form.Item label="内容" style={{ marginBottom: 0 }}>
                            <Form.Item
                                name="content"
                                style={{ display: 'inline-block',  'calc(100% - 8px)' }}
                                rules={[
                                    {
                                        required: true,
                                        message: "内容不能为空"
                                    }
                                ]}
                            >
                                <Editor
                                    editorState={this.state.editorState}
                                    wrapperClassName="demo-wrapper"
                                    editorClassName="demo-editor"
                                    onEditorStateChange={this.onEditorStateChange}
                                />
                                {/* <TextArea rows={4} /> */}
                            </Form.Item>
                        </Form.Item>
                    </Form>
                </Modal>

                <Modal
                    title="详情"
                    visible={this.state.showBlogModalVisible}
                    width={660}
                    onOk={this.handleShowBlogModalHandleOk}
                    onCancel={this.handleShowBlogModalHandleCancel}
                    okText="确定"
                    cancelText="取消"
                    maskClosable={false}
                    destroyOnClose={true}
                    footer={null}
                >

                    <div dangerouslySetInnerHTML={{__html: this.state.blogDetail}} style={{height: 300, overflow: 'auto'}}/>

                </Modal>
            </Card>
        </>
        )
    }
}
点击并拖拽以移动
原文地址:https://www.cnblogs.com/samve/p/14264547.html