自定义WYSIWYG编辑器选中文本保持选中状态时如何移除文本格式
自定义WYSIWYG编辑器保持选中状态切换格式实现方案
问题成因
现有逻辑核心缺陷为DOM修改后未主动同步更新选区范围:
- 首次点击格式按钮插入STRONG/EM标签后,选区仍停留在原文本节点位置,未指向新插入的格式标签。第二次点击时获取的
commonAncestorContainer.parentElement仍为外层段落标签,无法进入「已存在对应格式则移除」的判断分支 - 移除格式替换为纯文本节点后未更新选区,会出现选区丢失、后续操作失效问题
- 直接读取
commonAncestorContainer.parentElement判断格式的逻辑鲁棒性不足,跨节点选中文本时易出现判断错误。
修复后完整代码
JavaScript 逻辑
document.getElementById('bold').addEventListener('click', () => edit('STRONG')); document.getElementById('italic').addEventListener('click', () => edit('EM')); function edit(format) { const selection = document.getSelection(); if (!selection.rangeCount) return; const range = selection.getRangeAt(0); // 兼容文本节点、元素节点两种场景获取父元素 const parentElement = range.commonAncestorContainer.nodeType === 3 ? range.commonAncestorContainer.parentElement : range.commonAncestorContainer; // 已应用对应格式:执行移除 if (parentElement.tagName === format) { const grandParent = parentElement.parentElement; const textNode = document.createTextNode(parentElement.textContent); grandParent.insertBefore(textNode, parentElement); grandParent.removeChild(parentElement); grandParent.normalize(); // 重新设置选区到替换后的纯文本节点 const newRange = document.createRange(); newRange.selectNodeContents(textNode); selection.removeAllRanges(); selection.addRange(newRange); return; } // 未应用对应格式:执行添加 const formatNode = document.createElement(format); const fragment = range.extractContents(); formatNode.appendChild(fragment); range.insertNode(formatNode); // 重新设置选区到新插入的格式节点 const newRange = document.createRange(); newRange.selectNodeContents(formatNode); selection.removeAllRanges(); selection.addRange(newRange); }
HTML 结构
<button id="bold">B</button> <button id="italic">I</button> <p>Lorem ipsum</p>
关键改动点
- 新增选区存在性判断,兼容无选中内容、编辑器未聚焦的边界场景
- 修正父元素获取逻辑,同时兼容当前锚点为文本节点、元素节点两种情况
- 每次添加/移除格式的DOM操作完成后,主动创建新的Range实例选中操作后的目标节点内容,重新绑定到选区,保证连续点击按钮时选区始终落在正确节点上,可正常触发格式移除逻辑
内容的提问来源于stack exchange,提问作者xRay
相关产品推荐
相关产品推荐

