自制富文本编辑器HTML标签叠加实现及防覆盖问题求助
富文本编辑器格式化叠加与去重问题解决方案
核心问题分析
- 叠加效果丢失:当前用原始纯文本作为替换目标,第一次格式化后,目标文本被标签包裹,后续循环无法匹配到已格式化内容,导致只有最新修改生效。
- 重复添加标签:未判断目标文本是否已被对应格式标签包裹,重复点击会多次添加
<b>/<strong>标签。
解决方案
问题1:保留叠加格式
放弃基于原始纯文本的批量替换逻辑,改为直接在当前已格式化的文本上进行增量修改,或采用DOM操作利用浏览器原生API处理选区与格式叠加。
问题2:避免重复添加标签
在执行格式化前,先检查目标文本是否已被对应标签包裹,已包裹则取消格式,未包裹则添加格式。
推荐实现方案(DOM操作,稳定可靠)
利用浏览器Selection/RangeAPI直接操作编辑区域的DOM,自动处理格式叠加与标签去重,最后提取HTML存入数据库:
<!-- 富文本编辑器容器 --> <div id="richEditor" contenteditable="true" style="border:1px solid #ccc; padding:8px; min-height:100px;"></div> <button onclick="toggleBold()">加粗</button> <script> const editor = document.getElementById('richEditor'); let modifiedFullText = ''; // 最终存入数据库的HTML内容 function toggleBold() { const selection = window.getSelection(); if (!selection.rangeCount) return; const range = selection.getRangeAt(0); let boldElement = null; // 遍历选区祖先节点,检查是否已被加粗标签包裹 let currentNode = range.commonAncestorContainer; while (currentNode && currentNode !== editor) { if (currentNode.tagName === 'B' || currentNode.tagName === 'STRONG') { boldElement = currentNode; break; } currentNode = currentNode.parentNode; } if (boldElement) { // 取消加粗:将标签内容移至标签外,移除加粗标签 const parent = boldElement.parentNode; while (boldElement.firstChild) { parent.insertBefore(boldElement.firstChild, boldElement); } parent.removeChild(boldElement); } else { // 添加加粗:用<b>标签包裹选区内容 const boldTag = document.createElement('b'); try { range.surroundContents(boldTag); } catch (e) { // 处理跨节点选区(如选中多个不同标签的文本) const fragment = range.extractContents(); boldTag.appendChild(fragment); range.insertNode(boldTag); } } // 更新待存储的HTML内容 modifiedFullText = editor.innerHTML; console.log('待存储内容:', modifiedFullText); } </script>
字符串处理方案(适合无DOM场景)
若只能基于字符串操作,可通过正则匹配实现格式检查与替换:
// 转义正则特殊字符,避免匹配出错 const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); function handleBold() { const escapedText = escapeRegExp(selectedText.value); // 检查是否已被加粗标签包裹 const wrappedRegex = new RegExp(`<(b|strong)>${escapedText}</(b|strong)>`, 'i'); if (wrappedRegex.test(modifiedFullText.value)) { // 取消加粗:移除标签 modifiedFullText.value = modifiedFullText.value.replace(wrappedRegex, selectedText.value); // 更新格式化片段数组 formattedFragments.value = formattedFragments.value.filter(frag => !wrappedRegex.test(frag)); return; } // 检查是否存在未被包裹的目标文本 const plainTextRegex = new RegExp(`(${escapedText})`, 'i'); if (plainTextRegex.test(modifiedFullText.value.replace(/<[^>]+>/g, ''))) { // 添加加粗标签 modifiedFullText.value = modifiedFullText.value.replace(plainTextRegex, '<b>$1</b>'); formattedFragments.value.push(`<b>${selectedText.value}</b>`); } }
注意:字符串处理方案存在边缘场景限制(如文本重复、标签嵌套),优先推荐DOM操作方案。
内容的提问来源于stack exchange,提问作者user21903805
相关产品推荐
相关产品推荐

