react-quill集成quill-blot-formatter后编辑器滚动失效问题求助
解决Quill-Blot-Formatter导致React-Quill编辑器滚动失效的问题
问题概述
使用React-Quill编辑器,通过formats/image实现图片上传功能,为了添加图片缩放能力引入quill-blot-formatter并注册模块:Quill.register('modules/blotFormatter', BlotFormatter);。目前图片缩放功能正常,但鼠标处于缩放窗口内时,编辑器的滚动功能被禁用;鼠标移出缩放区域后,滚动恢复正常。推测是quill-blot-formatter的事件监听器阻止了鼠标事件冒泡到React-Quill的ql-editor元素。
参考代码
QuillEditor.js
import ReactQuill from 'react-quill'; const Quill = ReactQuill.Quill; const Embed = Quill.import('blots/embed'); import BlotFormatter from 'quill-blot-formatter/dist/BlotFormatter'; import { CustomImage } from './CustomPlugins/CustomImage'; // 注册自定义图片Blot Quill.register(CustomImage, true); // 注册图片缩放模块 Quill.register('modules/blotFormatter', BlotFormatter); <ReactQuill ref={editorRef} className={`w-full ${height} ${className} `} formats={formats} id={id} modules={modules(toolbarId)} theme="snow" value={state} onChange={handleChange} /> function modules(toolbarId) { return { blotFormatter: { specs: [CustomImageSpec], // 注册自定义规格 align: { icons: alignmentStyles, }, }, }; }
CustomImageSpec.js
import DeleteIcon from '../../../assets/DeleteIcon.svg'; import { alignToolBar } from './helper'; import ImageSpec from 'quill-blot-formatter/dist/specs/ImageSpec'; // 自定义图片规格,为工具栏添加删除按钮 export class CustomImageSpec extends ImageSpec { img; deleteIcon; constructor(formatter) { super(formatter); this.img = null; this.deleteIcon = this.createDeleteIcon(); } createDeleteIcon() { const spanElement = document.createElement('span'); const imgElement = document.createElement('img'); imgElement.src = DeleteIcon; imgElement.alt = 'test image'; const clsList = ['blot-formatter__toolbar-button', 'blot-delete-icon']; spanElement.classList.add(...clsList); spanElement.appendChild(imgElement); spanElement.style.cssText = 'display: flex; align-items:center; justify-content:center; width: 24px; height: 24px; cursor:pointer; user-select:none; padding: 2px'; spanElement.addEventListener('click', this.onDeleteIconClick); return spanElement; } init() { this.formatter.quill.root.addEventListener('click', this.onClick); this.formatter.quill.root.addEventListener('scroll', (e) => { this.formatter.repositionOverlay(); }); } getTargetElement() { return this.img; } onDeleteIconClick = () => { // 处理删除按钮点击逻辑 if (this.img) { this.img.remove(); this.formatter.hide(); } }; onHide() { this.img = null; } onClick = (event) => { const el = event.target; if (!el || el.tagName !== 'IMG') { return; } this.img = el; this.formatter.show(this); alignToolBar(this.formatter); this.formatter.overlay ?.getElementsByClassName('blot-formatter__toolbar')[0] ?.appendChild(this.deleteIcon); }; }
CustomImage.js
import { Quill } from 'react-quill'; const BaseImage = Quill.import('formats/image'); const ATTRIBUTES = ['alt', 'height', 'width', 'style']; export class CustomImage extends BaseImage { static formats(domNode) { return ATTRIBUTES.reduce(function (formats, attribute) { if (domNode.hasAttribute(attribute)) { formats[attribute] = domNode.getAttribute(attribute); } return formats; }, {}); } format(name, value) { if (ATTRIBUTES?.indexOf(name) > -1) { if (value) { this.domNode.setAttribute(name, value); } else { this.domNode.removeAttribute(name); } } else { super.format(name, value); } } } // 注册自定义图片Blot Quill.register(CustomImage, true);
解决方案
问题核心是quill-blot-formatter的遮罩层(overlay)默认会拦截鼠标滚轮事件,阻止其冒泡到编辑器容器。以下两种方法可解决该问题:
方法1:在CustomImageSpec中修改事件传递
在CustomImageSpec的init方法中,为遮罩层添加滚轮事件监听,允许事件继续冒泡:
init() { super.init(); // 必须调用父类初始化逻辑 this.formatter.quill.root.addEventListener('click', this.onClick); this.formatter.quill.root.addEventListener('scroll', (e) => { this.formatter.repositionOverlay(); }); // 允许滚轮事件冒泡到编辑器 this.formatter.overlay.addEventListener('wheel', (e) => { e.stopPropagation = false; e.cancelBubble = false; }, true); }
方法2:通过模块配置修改遮罩层行为
在注册blotFormatter模块时,直接配置遮罩层的事件处理:
function modules(toolbarId) { return { blotFormatter: { specs: [CustomImageSpec], align: { icons: alignmentStyles, }, overlay: { onCreated: (overlay) => { // 覆盖遮罩层的滚轮事件拦截逻辑 overlay.addEventListener('wheel', (e) => { e.stopImmediatePropagation(); const newEvent = new WheelEvent(e.type, e); this.formatter.quill.root.dispatchEvent(newEvent); }, true); } } }, }; }
补充处理
如果上述方法无效,说明quill-blot-formatter内部调用了e.preventDefault(),可通过以下方式强制解除拦截:
this.formatter.overlay.addEventListener('wheel', (e) => { e.stopImmediatePropagation(); e.preventDefault = () => {}; // 覆盖默认的阻止默认行为 }, true);
通过以上修改,鼠标在图片缩放窗口内时,滚轮事件将正常传递到React-Quill编辑器,恢复滚动功能。
内容的提问来源于stack exchange,提问作者Muthukumaran Ganapathy
相关产品推荐
相关产品推荐

