如何实现textarea与div块选中文本双向同步高亮显示
实现方案
实现逻辑
- 先保证textarea和preview区域的文本排版完全一致,避免选中位置出现偏移
- 分别监听两个区域的选中事件,获取选中文本的起止位置
- 加同步锁避免双向触发导致的死循环
- 将选中位置同步到另一个区域,实现双向高亮效果
完整修改代码
CSS代码
::-moz-selection { /* Code for Firefox */ color: red; background: yellow; } ::selection { color: red; background: yellow; } #preview { width:410px; border: solid 1px #999; padding:5px; /* 新增:保证和textarea的空格、换行排版完全一致 */ white-space: pre-wrap; word-break: break-all; min-height: 100px; } textarea { white-space: pre-wrap; word-break: break-all; }
JS代码
// 同步锁,避免双向触发循环 let isSyncing = false; function showPreview() { let value = $('textarea').val().trim(); // 修改为全局替换特殊字符 value = value.replace(/</g, "<").replace(/>/g, ">"); // 改用text方法赋值,保证只有单个文本节点,方便计算选中位置 $('#preview').text(value); } // 同步textarea的选中状态到preview function syncTextareaToPreview() { if (isSyncing) return; isSyncing = true; const textarea = $('textarea')[0]; const start = textarea.selectionStart; const end = textarea.selectionEnd; const preview = $('#preview')[0]; const textNode = preview.firstChild; const selection = window.getSelection(); if (!textNode || start === end) { selection.removeAllRanges(); isSyncing = false; return; } // 创建选中范围 const range = document.createRange(); range.setStart(textNode, start); range.setEnd(textNode, end); selection.removeAllRanges(); selection.addRange(range); isSyncing = false; } // 同步preview的选中状态到textarea function syncPreviewToTextarea() { if (isSyncing) return; isSyncing = true; const selection = window.getSelection(); const textarea = $('textarea')[0]; if (selection.rangeCount === 0) { textarea.selectionStart = textarea.selectionEnd = 0; isSyncing = false; return; } const range = selection.getRangeAt(0); const preview = $('#preview')[0]; // 校验选中区域是否在preview内部 if (!preview.contains(range.commonAncestorContainer)) { isSyncing = false; return; } // 赋值选中位置到textarea textarea.selectionStart = range.startOffset; textarea.selectionEnd = range.endOffset; isSyncing = false; } // 页面加载完成后绑定事件 $(function() { // 初始化预览内容 showPreview(); // 监听textarea选中相关事件 $('textarea').on('select keyup mouseup', syncTextareaToPreview); // 监听preview选中相关事件 $('#preview').on('mouseup keyup', syncPreviewToTextarea); })
HTML代码
保持原有结构不变即可。
注意事项
- 文本排版一致性是选中位置准确的前提,必须保留
white-space: pre-wrap属性 - 支持鼠标选中、键盘shift+方向键选中两种场景
- 同步锁避免了两个区域的选中事件互相触发导致的死循环问题
内容的提问来源于stack exchange,提问作者Ivan Dern
相关产品推荐
相关产品推荐

