当前位置: 首页 > news >正文

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

相关文章:

React wangEditor5 使用说明

1、支持包安装 yarn add wangeditor/editor # 或者 npm install wangeditor/editor --saveyarn add wangeditor/editor-for-react # 或者 npm install wangeditor/editor-for-react --save2、使用 import wangeditor/editor/dist/css/style.css // 引入 cssimport { useState…...

vue 实现数字验证码功能

需求&#xff1a;写了一个 手机发送验证码后 输入固定验证码的功能 封装成一个组件,如下: <template><div class"conts"><div class"box"><div class"code_list"><div :class"[ code_item, hideIndex 0 ? co…...

【计算机网络】HTTP协议详解(举例解释,超级详细)

文章目录 一、HTTP协议简单介绍 1、1 什么是HTTP协议 1、2 再次理解“协议” 二、HTTP请求 2、1 HTTP的工作过程 2、1、1 demo代码 2、2 URL 介绍 2、2、1 urlencode 和 urldecode 2、3 HTTP 请求格式 三、HTTP响应 3、1 响应demo 3、2 HTTP 响应格式 四、HTTP 请求和响应中的…...

PCB放置过孔技巧

合理的放置过孔能有效的节约面积。 我们根据嘉立创的pcb工艺能力中写出单双面板最小过孔为0.3mm(内径)/0.5mm(外径) 设置过孔尺寸外直径为24mil&#xff08;0.61mm&#xff09;&#xff09;内直径为12mil&#xff08;0.305mm&#xff09; 嘉立创PCB工艺加工能力范围说明-嘉立…...

淘宝商品详情接口数据采集用于上货,无货源选品上货,采集淘宝天猫商品详情数据

淘宝商品详情接口数据采集可用于上货。先通过关键字搜索接口&#xff0c;抓取到批量的商品ID&#xff0c;再将商品ID传入商品详情数据采集接口的请求参数中&#xff0c;从而达到批量抓取商品详情数据的功能。 接口名称&#xff1a;item_get&#xff0c;获取商品详情数据&#…...

DoS和DDos攻攻击

介绍 DDoS 和 DoS 攻击是我们最常见的网络攻击之一&#xff0c;而且历史相当悠久&#xff0c;算是很经典的两种攻击方式&#xff0c;但它们实际上是如何运作的呢&#xff1f; 虽然两者基本上都能够让工作停摆&#xff0c;但其中有很大的差异&#xff0c;接下来我们将逐一说明&a…...

Python实时采集Windows CPU\MEMORY\HDD使用率

文章目录 安装psutil库在Python脚本中导入psutil库获取CPU当前使用率&#xff0c;并打印结果获取内存当前使用率&#xff0c;并打印结果获取磁盘当前使用情况&#xff0c;并打印结果推荐阅读 要通过Python实时采集Windows性能计数器的数据&#xff0c;你可以使用psutil库。psut…...

【改造中序遍历算法】1038. 从二叉搜索树到更大和树

1038. 从二叉搜索树到更大和树 解题思路 改造中序遍历算法先遍历右子树 然后累加当前节点的值 再遍历左子树 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode…...

克服网络安全压力:如何掌控无限的云数据

管理云中的数字风险比以往任何时候都更加重要。数字化转型引发的云数据呈指数级增长&#xff0c;为安全分析师创造了一个更大的威胁环境。随着威胁行为者继续危害组织最敏感的数据&#xff0c;这一挑战将会加剧。 预计未来五年全球网络犯罪成本将激增&#xff0c;从 2022 年的…...

【数据结构和算法】--N叉树中,返回某些目标节点到根节点的所有路径

目录 一、前言二、具体实现及拓展2.1、递归-目标节点到根节点的路径数据2.2、list转换为tree结构2.3、tree转换为list结构 一、前言 这么多年工作经历中&#xff0c;“数据结构和算法”真的是超重要&#xff0c;工作中很多业务都能抽象成某种数据结构问题。下面是项目中遇到的…...

进程和线程的区别 线程之间共享的资源

线程和进程都是操作系统中的执行单位&#xff0c;但它们在以下几个方面存在区别&#xff1a; 相同处&#xff1a; 1.执行环境&#xff1a;线程和进程都有自己的执行上下文&#xff0c;包括程序计数器、寄存器和栈&#xff0c;可以独立执行指令。 2.并发性&#xff1a;线程和进…...

基于Matlab实现logistic方法(源码+数据)

Logistic回归是一种常用的分类算法&#xff0c;适用于二分类问题。本文将介绍如何使用Matlab实现Logistic回归方法&#xff0c;并通过一个示例演示其应用。 文章目录 引言实现步骤1. 数据准备2. 特征缩放3. 模型训练4. 模型评估 源码数据下载 引言 Logistic回归是一种广泛应用…...

leetCode 121. 买卖股票的最佳时机 贪心算法

给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…...

《Oracle系列》Oracle 索引使用情况查看

查询用户的索引 select index_name,table_name,tablespace_name,index_type,uniqueness,statusfrom dba_indexeswhere owner <用户名>;查询用户的索引列 select index_name,table_name,column_name,index_owner,table_ownerfrom dba_ind_columnswhere table_owner &l…...

解决Invalid bound statement (not found)错误~

报错如下所示&#xff1a; 找了好久&#xff0c;刚开始以为是名称哪里写的有问题&#xff0c;但仔细检查了好多遍都不是 最后发现了问题如下所示&#xff1a; UserMapper里面的内容被我修改了&#xff0c;但classes中的内容还是原来的内容&#xff0c;所以才导致了编译器报错n…...

基于SpringBoot的反诈宣传平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

【改进哈里鹰算法(NCHHO)】使用混沌和非线性控制参数来提高哈里鹰算法的优化性能,解决车联网相关的路由问题(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【C语言】宏定义

&#x1f6a9; WRITE IN FRONT&#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四"&#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评百大博…...

库存三层模型概述

库存分层 &#xff08;1&#xff09;电商库存体系分为三层&#xff1a;销售层、调度层、仓库层。 库存三层模型&#xff1a;销售库存&#xff0c;调度层属于订单领域-履约。实物库存属于库存领域 WMS的库存跟调度层是一致的。 但是销售库存跟调度层可能不一致&#xff0c;因为…...

SNERT预备队招新CTF体验赛-Web(SWCTF)

目录 1、F12 2、robots 3、game1-喂青蛙 4、game 2 - flap bird 5、game 3 - Clash 6、Get&Post 7、sql &#xff08;1&#xff09;手工注入 &#xff08;2&#xff09;工具注入 8、命令执行漏洞 9、文件上传漏洞 10、文件泄露 11、php反序列化漏洞 12、PHP绕…...

智能检索新范式,让AIAgent自主决策,提升RAG效率100%!

市面上的 RAG 系统&#xff0c;不管叫什么名字&#xff0c;本质上只有两种做法&#xff1a; 第一种&#xff0c;一次性检索。把用户的 query 向量化&#xff0c;从语料库里捞出 Top-K 个文档片段&#xff0c;拼成一个大 prompt 塞给模型。GraphRAG、HippoRAG、LightRAG 都属于…...

ARMv8 HFGITR_EL2寄存器解析与虚拟化指令陷阱控制

1. AArch64 HFGITR_EL2寄存器架构解析HFGITR_EL2&#xff08;Hypervisor Fine-Grained Instruction Trap Register&#xff09;是ARMv8架构中专门用于指令级陷阱控制的系统寄存器&#xff0c;属于虚拟化扩展的重要组成部分。这个64位寄存器通过位映射机制实现对特定AArch64指令…...

航空航天为什么离不开高强镁合金?国产替代到哪一步了

飞机每减重一千克&#xff0c;全年大约节省四千两百美元的燃油费用——这是航空工程师熟悉的经验值。在商业航空领域&#xff0c;这个数字还只是财务账&#xff1b;在战斗机、导弹和卫星的世界里&#xff0c;减重的收益被换算成更远的航程、更大的载荷、更高的机动性&#xff0…...

Unity UI交互进阶:手把手教你打造一个支持单击、双击、长按的万能按钮组件

Unity UI交互进阶&#xff1a;手把手教你打造一个支持单击、双击、长按的万能按钮组件在游戏开发中&#xff0c;UI交互的流畅性和多样性直接影响玩家的游戏体验。想象一下&#xff0c;当你在开发一个RPG游戏的背包系统时&#xff0c;需要实现道具的单击查看详情、双击快速使用、…...

为Claude Code配置稳定API源并解决访问限制

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 为Claude Code配置稳定API源并解决访问限制 Claude Code 作为一款强大的 AI 编程辅助工具&#xff0c;其原生服务在某些情况下可能…...

2026这6款神级降AIGC平台大公开,一键让AIGC率直逼绝对安全线!

步入 2026 年&#xff0c;学术圈的风向早已不是从前的模样。曾经大家还在为查重率发愁&#xff0c;如今却陷入了更棘手的困境——如何在不破坏论文专业性的前提下&#xff0c;彻底消除 AI 痕迹&#xff1f;随着 AIGC 检测技术不断进化&#xff0c;高校对论文的审核标准也愈发严…...

Java项目中如何提升整体系统性能?

性能优化可以说是我们程序员的必修课&#xff0c;如果你想要跳出CRUD的苦海&#xff0c;成为一个更“高级”的程序员的话&#xff0c;性能优化这一关你是无论无何都要去面对的。为了提升系统性能&#xff0c;开发人员可以从系统的各个角度和层次对系统进行优化。除了最常见的代…...

避坑指南:Unity中AABB碰撞检测失效的5种常见原因及解决方法

Unity中AABB碰撞检测失效的深度排查与解决方案在Unity开发中&#xff0c;AABB&#xff08;轴对齐包围盒&#xff09;碰撞检测是基础但容易出问题的环节。许多开发者都遇到过这样的情况&#xff1a;明明逻辑正确&#xff0c;测试时却出现物体穿透、碰撞时有时无等诡异现象。本文…...

为什么92%的数据库重构失败?Claude设计辅助如何在48小时内规避反范式陷阱?

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;为什么92%的数据库重构失败&#xff1f;——反范式陷阱的本质溯源 数据库重构失败率高达92%&#xff0c;其核心症结并非技术能力不足&#xff0c;而是对“反范式”这一设计策略的误读与滥用。许多团队在性能压…...

D2DX如何让暗黑破坏神2在4K显示器上流畅运行:5个关键技术解析

D2DX如何让暗黑破坏神2在4K显示器上流畅运行&#xff1a;5个关键技术解析 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 当…...