如何使用JavaScript实现textarea与div选中文本的同步高亮效果
文本选中同步高亮实现代码
前置说明
原生
<textarea>为纯文本表单控件,不支持内部插入HTML标签实现自定义局部高亮,因此以下实现提供两种可选方案,可根据实际需求选择:
- 方案1:保留原生
<textarea>,选中内容后仅同步高亮div内的匹配文本,textarea内选中区域使用浏览器默认选中样式 - 方案2:使用带
contenteditable属性的div模拟textarea功能,支持两个区块双向同步高亮匹配文本
方案1:保留原生textarea实现
完整可运行代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <style> /* 自定义高亮样式,可自行修改颜色 */ .highlight { background-color: #ffeb3b; color: #000; } textarea { width: 100%; height: 150px; margin: 10px 0; padding: 8px; box-sizing: border-box; } .content-div { border: 1px solid #ccc; padding: 8px; min-height: 150px; margin: 10px 0; } </style> </head> <body> <!-- 无id无class的textarea,符合需求 --> <textarea>测试文本内容,选中我看看效果,你可以随便修改这段文字,选中任意部分都会同步在下方div里高亮相同的内容哦。</textarea> <!-- 对应需要同步高亮的div --> <div class="content-div">测试文本内容,选中我看看效果,你可以随便修改这段文字,选中任意部分都会同步在下方div里高亮相同的内容哦。</div> <script> // 缓存原始div内容,用于清除高亮时恢复 let originDivContent = document.querySelector('.content-div').innerText; const textarea = document.querySelector('textarea'); const contentDiv = document.querySelector('.content-div'); // 清除所有高亮 function clearHighlight() { contentDiv.innerText = originDivContent; } // 高亮匹配文本 function highlightMatchedText(selectedText) { clearHighlight(); if (!selectedText.trim()) return; // 正则转义特殊字符 const escapedText = selectedText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const reg = new RegExp(escapedText, 'g'); contentDiv.innerHTML = originDivContent.replace(reg, '<span class="highlight">$&</span>'); } // 监听textarea选中事件 textarea.addEventListener('select', function() { const start = this.selectionStart; const end = this.selectionEnd; const selected = this.value.substring(start, end); highlightMatchedText(selected); }); // 监听div内的选中事件 contentDiv.addEventListener('mouseup', function() { const selection = window.getSelection ? window.getSelection() : document.getSelection(); const selected = selection.toString(); highlightMatchedText(selected); }); // 点击空白处清除高亮 document.addEventListener('click', function(e) { if (e.target !== textarea && e.target !== contentDiv && !contentDiv.contains(e.target)) { clearHighlight(); } }); // 同步textarea和div的内容,修改textarea时div内容同步更新 textarea.addEventListener('input', function() { originDivContent = this.value; contentDiv.innerText = originDivContent; }); </script> </body> </html>
方案2:contenteditable div模拟textarea(支持双向高亮)
如果需要两个区域都支持自定义高亮,可使用此方案,代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <style> .highlight { background-color: #ffeb3b; color: #000; } /* 模拟textarea样式 */ .simulate-textarea { width: 100%; height: 150px; margin: 10px 0; padding: 8px; border: 1px solid #ccc; box-sizing: border-box; overflow-y: auto; white-space: pre-wrap; word-break: break-all; outline: none; } .content-div { border: 1px solid #ccc; padding: 8px; min-height: 150px; margin: 10px 0; } </style> </head> <body> <!-- 模拟textarea的可编辑div --> <div class="simulate-textarea" contenteditable="true">测试文本内容,选中我看看效果,你可以随便修改这段文字,选中任意部分都会同步在另一个区块里高亮相同的内容哦。</div> <!-- 对应需要同步高亮的div --> <div class="content-div">测试文本内容,选中我看看效果,你可以随便修改这段文字,选中任意部分都会同步在另一个区块里高亮相同的内容哦。</div> <script> const editArea = document.querySelector('.simulate-textarea'); const contentDiv = document.querySelector('.content-div'); // 缓存原始内容 let originEditContent = editArea.innerText; let originDivContent = contentDiv.innerText; function clearAllHighlight() { editArea.innerText = originEditContent; contentDiv.innerText = originDivContent; } function highlightBoth(selectedText) { clearAllHighlight(); if (!selectedText.trim()) return; const escapedText = selectedText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const reg = new RegExp(escapedText, 'g'); editArea.innerHTML = originEditContent.replace(reg, '<span class="highlight">$&</span>'); contentDiv.innerHTML = originDivContent.replace(reg, '<span class="highlight">$&</span>'); } // 监听两个区域的选中事件 [editArea, contentDiv].forEach(el => { el.addEventListener('mouseup', function() { const selection = window.getSelection ? window.getSelection() : document.getSelection(); const selected = selection.toString(); highlightBoth(selected); }); // 内容同步 el.addEventListener('input', function() { const newContent = this.innerText; originEditContent = newContent; originDivContent = newContent; editArea.innerText = newContent; contentDiv.innerText = newContent; }); }); // 点击空白清除高亮 document.addEventListener('click', function(e) { if (e.target !== editArea && e.target !== contentDiv && !contentDiv.contains(e.target) && !editArea.contains(e.target)) { clearAllHighlight(); } }); </script> </body> </html>
内容的提问来源于stack exchange,提问作者Ivan Dern
相关产品推荐
相关产品推荐

