需求:添加按钮,点击出弹窗
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;
}
}
最主要的一步就是将控制弹窗显示的方法传递给工具栏的按钮