活力39282
在线时间13640 小时
阅读权限200
管理员
自由的灵魂
- 积分
- 107434
- 主题
- 5630
- 回帖
- 26661
- 注册时间
- 2003-4-10
- 最后登录
- 2026-10-2
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
当前版本:Discuz X3.5
1、问题缘起
论坛发帖编辑器存在一个问题:在所见即所得(WYSIWYG)模式下,每次从纯文本模式切换回可视化模式后,粘贴操作都会将剪贴板内容重复插入多次。
具体现象:
| 场景 | 粘贴结果 | 说明 | | 初次进入可视化编辑器 | 粘贴出 1 份内容(A) | 正常 | | 切换到纯文本模式,再切回可视化模式 | 粘贴出 2 份内容(AA) | 异常 | | 再切换到纯文本模式,再切回可视化模式 | 粘贴出 3 份内容(AAA) | 异常 |
根本原因:setEditorEvents() 函数在每次切换到可视化模式时都会被调用,其中包含的 paste 事件监听器使用匿名函数,导致每次调用都会新增一个监听器,而旧的监听器没有被移除。多次切换后,同一个 paste 事件触发了多个监听器,导致粘贴内容被重复插入。
相关子问题:
- 纯文本模式下粘贴正常,不受影响
- 问题仅在切换到可视化模式后出现
- 切换次数与重复次数成正比
2、解决方案
(1)简要技术分析:
使用一个全局标志变量 window._pasteBound 记录 paste 监听器是否已被绑定,确保在整个页面生命周期中只绑定一次,避免重复添加。
(2)修改文件列表:
| 操作 | 文件路径 | | 修改 | /static/js/editor.js |
(3)关键代码段:
修改一:在 setEditorEvents 函数开头添加标志变量(约第 230 行)
- function setEditorEvents() {
- // ----- 防止 paste 监听器重复绑定 -----
- if (typeof window._pasteBound === 'undefined') {
- window._pasteBound = false;
- }
- // ------------------------------------------
- // ... 后续代码
- }
复制代码
修改二:将原有匿名 paste 监听器包裹在条件判断中(约第 238 行)
- // ----- paste 事件监听(仅绑定一次) -----
- if (!window._pasteBound) {
- editdoc.addEventListener('paste', function(e) {
- var clipboardData = e.clipboardData || window.clipboardData;
- if (!clipboardData) return;
- var text = clipboardData.getData('text/plain');
- if (text) {
- e.preventDefault();
- if (wysiwyg) {
- editdoc.execCommand('insertText', false, text);
- } else {
- var start = editdoc.selectionStart;
- var end = editdoc.selectionEnd;
- var value = editdoc.value;
- editdoc.value = value.substring(0, start) + text + value.substring(end);
- editdoc.selectionStart = editdoc.selectionEnd = start + text.length;
- }
- }
- }, true);
- window._pasteBound = true;
- }
- // -------------------------------------------------
复制代码
3、最终实现效果
| 测试场景 | 修复前 | 修复后 | | 初次进入可视化编辑器后粘贴 | 1 份内容 | 1 份内容 | | 切纯文本→切回可视化后粘贴 | 2 份内容 | 1 份内容 | | 再切纯文本→再切回可视化后粘贴 | 3 份内容 | 1 份内容 | | 多次切换后粘贴 | 重复次数递增 | 始终 1 份内容 |
所有切换模式下粘贴行为保持一致,内容不再重复。
4、重要技术沉淀
需更新到固化摘要:
- 二十四、编辑器 paste 事件监听重复绑定问题(2026-08-27)
- 问题:切换编辑器模式后粘贴内容重复
- 原因:setEditorEvents() 每次调用都会添加新的匿名 paste 监听器
- 解决:使用全局标志 window._pasteBound 控制监听器只绑定一次
- 涉及文件:static/js/editor.js
- 排查方法:切换模式次数与粘贴重复次数成正比,即可判断为监听器重复绑定
复制代码
踩坑点:
| 踩坑 | 正确做法 | | 用 removeEventListener 移除匿名函数 | 匿名函数无法被移除,应使用命名函数或标志控制 | | 在 switchEditor 中清空编辑器内容 | 会导致用户正在编辑的内容丢失,不可取 | | 每次切换都重新绑定监听器 | 用标志控制只绑定一次,或在初始化时统一绑定 |
5、进一步优化可能性
- 将 paste 监听器从 setEditorEvents 中分离:在编辑器初始化时统一绑定,避免与模式切换逻辑耦合
- 使用命名函数替代标志控制:用 handlePaste 命名函数配合 removeEventListener 实现更精确的移除
- 检查其他事件的重复绑定:mouseup、keyup 等事件是否存在类似问题
|
|