React wangEditor5 使用说明

1、支持包安装

yarn add @wangeditor/editor
# 或者 npm install @wangeditor/editor --saveyarn add @wangeditor/editor-for-react
# 或者 npm install @wangeditor/editor-for-react --save

2、使用

import '@wangeditor/editor/dist/css/style.css' // 引入 cssimport { useState, useEffect } from 'react'
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'type InsertImgType = (url: string, alt: string, href: string) => void;
type InsertVideoType = (url: string, poster?: string) => void;const MyEditor: FunctionComponent = () => {// editor 实例const [editor, setEditor] = useState<IDomEditor | null>(null);// 编辑器内容const [html, setHtml] = useState('<p>hello</p>')// 模拟 ajax 请求,异步设置 htmluseEffect(() => {setTimeout(() => {setHtml('<p>hello world</p>')}, 1500)}, [])// 工具栏配置const toolbarConfig: Partial<IToolbarConfig> = {excludeKeys: ['group-video']};// 编辑器配置const editorConfig: Partial<IEditorConfig> = {placeholder: '请输入内容...',readOnly: false,MENU_CONF: {uploadImage: {// 自定义上传 -- 图片customUpload: (file: File, insertFn: InsertImgType) => {if(file.type.startsWith('image/')) {// file 即选中的文件// 自己实现上传,并得到图片 url alt href// 最后插入图片insertFn(url, alt, href)} else {// 错误提示}}},uploadVideo: {// 自定义上传 -- 视频customUpload: (file: File, insertFn: InsertVideoType) => {// file 即选中的文件// 自己实现上传,并得到视频 url poster// 最后插入视频insertFn(url, poster)}}}}useEffect(() => {// 修改弹窗位置为编译器居中editor?.on('modalOrPanelShow', modalOrPanel => {if (modalOrPanel.type !== 'modal') returnconst { $elem } = modalOrPanel; // modal elementconst width = $elem.width();const height = $elem.height();// set modal position z-index$elem.css({left: '50%',top: '50%',bottom: 'auto',  // 需要修改底部间距,不然会受组件自身计算影响marginLeft: `-${width / 2}px`,marginTop: `-${height / 2}px`,zIndex: 1000});});// 及时销毁 editor ,重要!return () => {if (editor == null) returneditor.destroy()setEditor(null)}}, [editor])return (<><div style={{ border: '1px solid #ccc', zIndex: 100}}><Toolbareditor={editor}defaultConfig={toolbarConfig}mode="default"style={{ borderBottom: '1px solid #ccc' }}/><EditordefaultConfig={editorConfig}value={html}onCreated={setEditor}onChange={editor => setHtml(editor.getHtml())}mode="default"style={{ height: '500px', overflowY: 'hidden' }}/></div></>)
}export default MyEditor;

3、自定义菜单

1. 添加自定义菜单弹窗

import { DomEditor, IDomEditor, IModalMenu, SlateNode, SlateTransforms, t } from '@wangeditor/editor';
import { DOMElement } from '@wangeditor/editor/dist/editor/src/utils/dom';
import { genModalButtonElems, genModalInputElems } from './utils';class EditImageSize implements IModalMenu {showModal: boolean;modalWidth: number;title: string;iconSvg?: string;hotkey?: string;alwaysEnable?: boolean;tag: string;width?: number;private $content: DOMElement | null = null;private getSelectedImageNode(editor: IDomEditor): SlateNode | null {return DomEditor.getSelectedNodeByType(editor, 'image')}constructor() {this.title = t('videoModule.editSize');// this.iconSvg = '<svg >...</svg>';this.tag = 'button';this.showModal = true;this.modalWidth = 320;}// 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 falseisActive(): boolean {// 任何时候,都不用激活 menureturn false}// 获取菜单执行时的 value ,用不到则返回空 字符串或 falsegetValue(): string | boolean {// 插入菜单,不需要 valuereturn ''}// 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 falseisDisabled(editor: IDomEditor): boolean {if (editor.selection == null) return trueconst videoNode = this.getSelectedImageNode(editor)if (videoNode == null) {// 选区未处于 image node ,则禁用return true}return false}// 点击菜单时触发的函数exec() {// 点击菜单时,弹出 modal 之前,不需要执行其他代码// 此处空着即可}// 弹出框 modal 的定位:1. 返回某一个 SlateNode; 2. 返回 null (根据当前选区自动定位)getModalPositionNode(editor: IDomEditor): SlateNode | null {return this.getSelectedImageNode(editor);}// 定义 modal 内部的 DOM ElementgetModalContentElem(editor: IDomEditor): DOMElement {const $content = this.$content || document.createElement('div');const [inputWidthContainerElem, inputWidthElem] = genModalInputElems(t('videoModule.width'),`input-width-${Math.random().toString(36).slice(2)}`,'auto');const [inputHeightContainerElem, inputHeightElem] = genModalInputElems(t('videoModule.height'),`input-height-${Math.random().toString(36).slice(2)}`,'auto');const buttonContainerElem = genModalButtonElems(`button-${Math.random().toString(36).slice(2)}`,t('videoModule.ok'));$content.append(inputWidthContainerElem);$content.append(inputHeightContainerElem);$content.append(buttonContainerElem);const imageNode = this.getSelectedImageNode(editor) as unknown as HTMLElement;// 绑定事件(第一次渲染时绑定,不要重复绑定)if (this.$content == null) {buttonContainerElem.onclick = () => {const width = Number(inputWidthElem.value);const height = Number(inputHeightElem.value);console.log(editor, isNaN(width) ? inputWidthElem.value : width ? width +'px' : 'auto', isNaN(height) ? inputHeightElem.value : height ? height +'px' : 'auto')editor.restoreSelection();// 修改尺寸SlateTransforms.setNodes(editor,{style: {width: isNaN(width) ? inputWidthElem.value : width ? width +'px' : 'auto',height: isNaN(height) ? inputHeightElem.value : height ? height +'px' : 'auto',}} as any,{match: n => DomEditor.checkNodeType(n, 'image'),})editor.hidePanelOrModal(); // 隐藏 modal}}if (imageNode == null) return $content;// 初始化 input 值const { width = 'auto', height = 'auto' } = imageNode.style;inputWidthElem.value = width || 'auto';inputHeightElem.value = height || 'auto';setTimeout(() => {inputWidthElem.focus()});return $content // 返回 DOM Element 类型// PS:也可以把 $content 缓存下来,这样不用每次重复创建、重复绑定事件,优化性能}
}export const EditImageSizeConf = {key: 'editImageSize', // 定义 menu key :要保证唯一、不重复(重要)factory() {return new EditImageSize() // 把 `YourMenuClass` 替换为你菜单的 class},
}

公用工具utils

// 生成输入框
export const genModalInputElems = (label: string, id: string, val: string): [HTMLLabelElement, HTMLInputElement] => {const $label = document.createElement('label');$label.className = 'babel-container';const $span = document.createElement('span');$span.textContent = label;const $input = document.createElement('input');$input.type = 'text';$input.id = id;$input.value = val;$label.append($span);$label.append($input);return [$label, $input];
};// 生成按钮
export const genModalButtonElems = (id: string, text: string) => {const $content = document.createElement('div');$content.className = 'button-container';const $button = document.createElement('button');$button.id = id;$button.textContent = text;$content.append($button);return $content;
};

2. 注册自定义菜单

  // 注册自定义菜单useEffect(() => {try  {Boot.registerMenu(EditImageSizeConf);} catch (e) {}}, [])

3. 挂载到工具栏

  // 工具栏配置const toolbarConfig: Partial<IToolbarConfig> = {insertKeys: {index: 5, // 插入的位置,基于当前的 toolbarKeyskeys: ['editImageSize']}}

4. 挂载到组件hover菜单

  // 编辑器配置const editorConfig: Partial<IEditorConfig> = {hoverbarKeys: {image: {menuKeys: ['editImageSize']  // 注意:要保留原有的菜单需加上之前的菜单key}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/94040.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS鼠标指针表

(机翻)搬运自:cursor - CSS: Cascading Style Sheets | MDN (mozilla.org) 类型Keyword演示注释全局autoUA将基于当前上下文来确定要显示的光标。例如&#xff0c;相当于悬停文本时的文本。default 依赖于平台的默认光标。通常是箭头。none不会渲染光标。链接&状态contex…

对示例程序spinner_asyncio.py进行修改使其能运行

学习《流畅的python》第18章 使用asyncio包处理并发&#xff0c;运行示例18-2 spinner_asyncio.py的时候&#xff0c;程序报错如下&#xff1a; D:\fluentPy\chapter17>python spinner_asyncio.py File "D:\fluentPy\chapter17\spinner_asyncio.py", line 30 …

python:xlrd 读取 Excel文件,显示在 tkinterTable 表格中

pip install xlrd 摘要: Library for developers to extract data from Microsoft Excel (tm) spreadsheet files pip install tkinterTable tkintertable-1.3.3.tar.gz (58 kB) 摘要: Extendable table class for Tkinter 源代码链接&#xff1a;https://github.com/dmnf…

正则表达式基本使用

文章目录 1. 基本介绍2. 元字符(Metacharacter)-转义号 \\3. 元字符-字符匹配符3.1 案例 4. 元字符-选择匹配符5. 元字符-限定符6. 元字符-定位符7. 分组7.1 捕获分组7.2 非捕获分组 8. 非贪婪匹配9. 应用实例10. 正则验证复杂URL 1. 基本介绍 如果要想灵活的运用正则表达式&a…

多线程基础篇(多线程案例)

文章目录 多线程案例1、单例模式1&#xff09;饿汉模式2&#xff09;懒汉模式3&#xff09;线程安全吗&#xff1f;&#xff1f;4&#xff09;解决懒汉模式线程安全问题5&#xff09;解决懒汉模式内存可见性问题 2、阻塞队列1) 阻塞队列是什么&#xff1f;2) 生产者消费者模型1…

用向量数据库Milvus Cloud搭建检索知识库机器人

检索知识库 Milvus 中已经存储了文本块向量,现在可以进行向量查询了。 以下函数创建了 1 个查询 pipeline。注意,这是本教程中最为关键的一个步骤! ops.ann_search.osschat_milvus(host=MILVUS_HOST, port=MILVUS_PORT, **{metric_type: IP, limit: 3, output_fields: [text…

全新UI彩虹外链网盘系统源码(前后端美化模板)

全新UI彩虹外链网盘系统源码前后端美化模板&#xff0c;支持所有格式文件的上传、生成文件外链、图片外链、音乐视频外链等功能&#xff0c;同时还可以自动生成相应的 UBB 代码和 HTML 代码&#xff0c;支持文本、图片、音乐、视频在线预览。这不仅仅是一个网盘&#xff0c;更是…

redis的简单使用

文章目录 环境安装与配置redis发布-订阅相关命令redis发布-订阅的客户端编程redis的订阅发布的例子 环境安装与配置 sudo apt-get install redis-server # ubuntu命令安装redis服务ubuntu通过上面命令安装完redis&#xff0c;会自动启动redis服务&#xff0c;通过ps命令确认&a…

【Linux】进程控制基础知识

目录 一&#xff0c;fack回顾 二&#xff0c;进程终止 1.进程终止&#xff0c;操作系统做了什么&#xff1f; 2.进程终止&#xff0c;常见的方式 1.main函数的&#xff0c;return 返回码 2. exit()函数 三&#xff0c;进程等待 1. 回收进程方法 &#xff08;1. wai…

【单片机】16-LCD1602和12864显示器

1.LCD显示器相关背景 1.LCD简介 &#xff08;1&#xff09;显示器&#xff0c;常见显示器&#xff1a;电视&#xff0c;电脑 &#xff08;2&#xff09;LCD&#xff08;Liquid Crystal Display&#xff09;&#xff0c;液晶显示器&#xff0c;原理介绍 &#xff08;3&#xff…

国庆10.03

运算符重载 代码 #include <iostream> using namespace std; class Num { private:int num1; //实部int num2; //虚部 public:Num(){}; //无参构造Num(int n1,int n2):num1(n1),num2(n2){}; //有参构造~Num(){}; //析构函数const Num operator(const Num &other)co…

【计算机网络笔记十】计算机网络面试问题总结

1. 计算机网络的各层协议及作用&#xff1f; 计算机网络体系可以大致分为一下三种&#xff0c;OSI 七层模型、TCP/IP 四层模型和五层模型。 OSI 七层模型&#xff1a;大而全&#xff0c;但是比较复杂、而且是先有了理论模型&#xff0c;没有实际应用。TCP/IP 四层模型&#x…

[前端基础]typescript安装以及类型拓展

&#xff08;0&#xff09;写在前面&#xff1a; 作者之前都是在写js&#xff0c;所以这里介绍ts肯定是不能从头开始介绍了&#xff0c;主要在js的基础上介绍ts关于类型的几个特性&#xff0c;以及ts的安装还有配置问题 &#xff08;1&#xff09;ts和js是什么关系 通俗点来…

数据分析笔记1

数据分析概述&#xff1a;数据获取--探索分析与可视化--预处理--分析建模--模型评估 数据分析含义&#xff1a;利用统计与概率的分析方法提取有用的信息&#xff0c;最后进行总结与概括 一、数据获取 实用网站&#xff1a;kaggle 阿里云天池 数据仓库&#xff1a;将所有业务数据…

Java之SpringCloud Alibaba【六】【Alibaba微服务分布式事务组件—Seata】

一、事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 在关系数据库中&#xff0c;一个事务由一组SQL语句组成。 事务应该具有4个属性: 原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性(atomicity) ∶个事务…

【Leetcode】 131. 分割回文串

给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例 1&#xff1a; 输入&#xff1a;s "aab" 输出&#xff1a;[["a","a"…

网站白屏优化

网站白屏优化 <div v-foritem in 10000><child></child> </div>比如要渲染当前页面&#xff0c;会很慢&#xff0c;页面上出现长时间的白屏&#xff0c;因为要渲染10000次child组件。 我们提供的解决方案是按帧加载Dom。 使用按帧加载就不得不提到req…

Leetcode 662. 二叉树最大宽度

文章目录 题目代码&#xff08;9.30 首刷看解析&#xff09; 题目 Leetcode 662. 二叉树最大宽度 代码&#xff08;9.30 首刷看解析&#xff09; class Solution { public:int widthOfBinaryTree(TreeNode* root) {unsigned long long res 1;using pr pair<TreeNode*, u…

【面试题精讲】注释有哪几种形式

“ 有的时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能会未同步,认准https://blog.zysicyj.top ” 首发博客地址[1] 面试题手册[2] 系列文章地址[3] 1. 什么是 Java 注释? Java 注释是一种用于在代码中添加说明和解释的特殊文本。它们不会被编…

Doctest:让你的测试更简单高效

简介&#xff1a;Doctest 是 Python 标准库的一部分&#xff0c;它允许开发者通过在文档字符串&#xff08;docstrings&#xff09;中编写示例来进行测试。这不仅可以在确保代码正确性的同时编写文档&#xff0c;还可以让读者更容易理解代码的用法和期望的输出。 历史攻略&…