react函数式组件中wangeditor自定义菜单

需求:添加按钮,点击出弹窗

1.不知道key写哪

参考了工具栏配置 | wangEditor文档,采用插入的方法配置,但是不知道keys定义的值写在哪。。。

toolbarConfig.insertKeys = {
    index: 5, // 插入的位置,基于当前的 toolbarKeys
    keys: ['menu-key1', 'menu-key2']
}

解决:后面看到一篇文章,wangEditor自定义菜单遇到 Uncaught (in promise) Error: Duplicated key ‘clearAll‘ in menu items_duplicated key 'uploadattachment' in menu items-CSDN博客,是采用vue的方式去实现的,大概知道要先去定义类然后将key值注册到菜单栏中

2.重复key多次执行

然后,就报了另一个错误。。。

Duplicated key 'myButton' in menu items

大概意思就是重复注册了,一开始想试着用上面文章中的方法去解决,于是有了两个问题:

// 1.不知道该放哪执行editor不为null,并且只执行一次

  // 2.按钮添加key值上去不显示

一个是不知道哪个阶段editor会有值,一个就是React不像Vue那样双向绑定数据,视图实时更新

解决:然后我又看到了一篇文章,reac基于wangEditor编辑器实现自定义菜单项插入变量_wangeditor插入变量-CSDN博客,解决了这个报错,工具栏上显示出插入进去的按钮了。后面就开始做弹窗部分,我给想简单了

3.不知道怎么调用弹窗的显示方法

import '@wangeditor/editor/dist/css/style.css' // 引入 css

import React, { useState, useEffect } from 'react'

import { Boot } from "@wangeditor/editor";
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import { Button, Modal } from 'antd';

class MyButtonMenu {
    constructor() {
        this.title = "阿巴阿巴"; // 自定义菜单标题
        this.tag = "button";
    }


    // 获取菜单执行时的 value ,用不到则返回空 字符串或 false
    getValue(editor) {
    }

    // 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 false
    isActive(editor) {
        // JS 语法
        return false;
    }

    // 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 false
    isDisabled(editor) {
        // JS 语法
        return false;
    }

    // 点击菜单时触发的函数
    exec(editor, value) {
        // MyEditor.showModal();
        // JS 语法
        editor.clear();
    }
}
const menu1Conf = {
    key: "myButton", // 定义 menu key :要保证唯一、不重复(重要)
    factory() {
        return new MyButtonMenu();
    },
};
Boot.registerMenu(menu1Conf);
function MyEditor(props) {
    const [isModalOpen, setIsModalOpen] = useState();
    useEffect(() => {
        if (props != {}) {
            props.onInit(setIsModalOpen);
        }
    }, []);
    const showModal = () => {
        setIsModalOpen(true);
      };
    const handleOk = () => {
        setIsModalOpen(false);

    };
    const handleCancel = () => {
        setIsModalOpen(false);
    };

    // editor 实例
    // const [editor, setEditor] = useState<IDomEditor | null>(null)   // TS 语法
    const [editor, setEditor] = useState(null)                // JS 语法
    // 编辑器内容
    const [html, setHtml] = useState('<p>hello</p>')
    // const [toolbarConfig, setToolbarConfig] =useState({})

    // 模拟 ajax 请求,异步设置 html
    useEffect(() => {
        setTimeout(() => {
            setHtml('<p>hello world</p>')
        }, 1500)
    }, [])

    // 工具栏配置
    // const toolbarConfig: Partial<IToolbarConfig> = { }  // TS 语法
    const toolbarConfig = {

    }                        // JS 语法
    toolbarConfig.insertKeys = {
        index: 35, // 插入的位置,基于当前的 toolbarKeys
        keys: ['myButton']
    }
    // 需要让editor不是null才能执行方法并且只执行一次

    const editorConfig = {                         // JS 语法
        placeholder: '请输入内容...',
    }

    // 及时销毁 editor ,重要!
    useEffect(() => {
        return () => {
            if (editor == null) return
            editor.destroy()
            setEditor(null)
        }
    }, [editor])

    return (
        <>
            <div style={{ border: '1px solid #ccc', zIndex: 100 }}>
                <Toolbar
                    editor={editor}
                    defaultConfig={toolbarConfig}
                    mode="default"
                    style={{ borderBottom: '1px solid #ccc' }}
                />
                <Editor
                    defaultConfig={editorConfig}
                    value={html}
                    onCreated={setEditor}
                    onChange={editor => setHtml(editor.getHtml())}
                    mode="default"
                    style={{ height: '500px', overflowY: 'hidden' }}
                />
            </div>
            <div style={{ marginTop: '15px' }}>
                {html}
            </div>
            {/* <Button type="primary" onClick={showModal}>
        Open Modal
      </Button> */}
            <Modal title="Basic Modal" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
                <p>Some contents...</p>
                <p>Some contents...</p>
                <p>Some contents...</p>
            </Modal>
        </>
    )
}

export default MyEditor

然后,乱七八糟试了一通,开始寻找类似文章进行解决

解决:

此贴为了展示在react中更方便的扩展menu,替代原有的modalMenu方案。 · Issue #4598 · wangeditor-team/wangEditor · GitHub

最后,采用该方法,弹窗出来了

import '@wangeditor/editor/dist/css/style.css' // 引入 css

import React, { useState, useEffect } from 'react'

import { Boot } from "@wangeditor/editor";
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import CsModal from './CsModal';
import BaseModalMenu from './BaseModalMenu';

 class ModalMenu extends BaseModalMenu {
    constructor() {
        super();
    }

    getValue(editor) {
        return <CsModal onInit={this.modalInit}  />
    }
}

const myModalMenuConf = {
    key: 'myModalMenu',
    factory() {
        return new ModalMenu()
    }
}
Boot.registerMenu(myModalMenuConf)

function MyEditor() {
    
    // editor 实例
    // const [editor, setEditor] = useState<IDomEditor | null>(null)   // TS 语法
    const [editor, setEditor] = useState(null)                // JS 语法
    // 编辑器内容
    const [html, setHtml] = useState('<p>hello</p>')
    // const [toolbarConfig, setToolbarConfig] =useState({})

    // 模拟 ajax 请求,异步设置 html
    useEffect(() => {
        setTimeout(() => {
            setHtml('<p>hello world</p>')
        }, 1500)
    }, [])

    // 工具栏配置
    // const toolbarConfig: Partial<IToolbarConfig> = { }  // TS 语法
    const toolbarConfig = {

    }                        // JS 语法
    toolbarConfig.insertKeys = {
        index: 66, // 插入的位置,基于当前的 toolbarKeys
        keys: ['myModalMenu']
    }

    // 编辑器配置
    // const editorConfig: Partial<IEditorConfig> = {    // TS 语法
    const editorConfig = {                         // JS 语法
        placeholder: '请输入内容...',
    }

    // 及时销毁 editor ,重要!
    useEffect(() => {
        return () => {
            if (editor == null) return
            editor.destroy()
            setEditor(null)
        }
    }, [editor])

    return (
        <>
            <div style={{ border: '1px solid #ccc', zIndex: 100 }}>
                <Toolbar
                    editor={editor}
                    defaultConfig={toolbarConfig}
                    mode="default"
                    style={{ borderBottom: '1px solid #ccc' }}
                />
                <Editor
                    defaultConfig={editorConfig}
                    value={html}
                    onCreated={setEditor}
                    onChange={editor => setHtml(editor.getHtml())}
                    mode="default"
                    style={{ height: '500px', overflowY: 'hidden' }}
                />
            </div>
            <div style={{ marginTop: '15px' }}>
                {html}
            </div>
        </>
    )
}

export default MyEditor

//CsModal.jsx

import { Modal } from 'antd';
import { useEffect, useState } from 'react';

export default function CsModal(props) {
    const [isModalVisible, setIsModalVisible] = useState(true);
    const close = () => {
        setIsModalVisible(false);
    }
    
    useEffect(() => {
        console.log(props.onInit,"6789")
        props?.onInit(setIsModalVisible); 
    }, []);
    
    return <Modal title="Basic Modal" visible={isModalVisible} onOk={close} onCancel={close}>
        <p>Some contents...</p>
        <p>Some contents...</p>
        <p>Some contents...</p>
    </Modal>
}

//BaseModalMenu.js

import ReactDOM from "react-dom/client";

export default class BaseModalMenu {
    // id: string = `modal-${Math.random().toString(36).slice(2)}`
    // title: string
    // tag: string
    // $ele: HTMLDivElement;
    // $root: any
    // ifInit: boolean = false;
    // controlShow: (i: boolean) => void = Function.prototype as any;
    
    constructor() {
        this.title = 'My Modal';
        // this.iconSvg = '<svg >...</svg>'; icon
        this.tag = 'button';
        this.$ele = document.createElement('div');
        this.$ele.id = this.id;
        document.body.appendChild(this.$ele);
        this.$root = ReactDOM.createRoot(this.$ele);
    }

    modalInit = (method) => {
        // 这里把控制react的方法透出
        this.controlShow = method;
    }


    isActive(editor) {
        return false // or false
    }

    isDisabled(editor) {
        return false // or true
    }

    exec(editor, value) {

        if (this.ifInit) {
            this.controlShow(true);
            return;
        }
        // editor.insertText(value)
        this.$root.render(
            value,
        );
        this.ifInit = true;
    }
}

最主要的一步就是将控制弹窗显示的方法传递给工具栏的按钮

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值