如何在编辑器中高亮光标所在行的行号
解决编号div中高亮当前活动行的问题
你遇到的问题是能获取textarea的当前行号,但无法正确给编号div对应的行添加背景高亮,核心原因是事件覆盖不全、未清除历史高亮、边界场景处理缺失,以下是修复方案:
修复要点
- 补充事件监听:仅监听click事件不够,要覆盖键盘移动光标、输入内容、鼠标选中等场景,添加
input、keydown、mouseup事件。 - 清除历史高亮:每次高亮新行前,先把所有行号span的背景色重置,避免多个行同时高亮。
- 处理边界行号:当光标在最后一行末尾时,行号计算会超出数组索引,需要修正行号值。
- 行号更新后同步高亮:更新行号列表后,重新高亮当前行,保证行号变化后高亮状态不丢失。
完整代码
HTML
<body> <div class="editor"> <div class="numbers"> <span></span> </div> <textarea wrap="off" id="textarea" rows="10" cols="50" onkeyup="updateRowNumbering(this)"></textarea> </div> </body>
CSS
body, textarea { font-family: Consolas, "Courier New", Courier, monospace; } .editor { display: inline-grid; grid-template-columns: 3em auto; gap: 10px; line-height: 21px; background: rgb(40 42 58); border-radius: 2px; overflow-y: auto; max-height: 243px; } .editor>* { padding-top: 10px; padding-bottom: 10px; } .numbers { text-align: right; background: #333; padding-right: 5px; } .numbers span { counter-increment: linenumber; } .numbers span::before { content: counter(linenumber); display: block; color: #888; } textarea { line-height: 21px; border: 0; background: transparent; color: #fff; min-width: 500px; outline: none; resize: none; padding-right: 10px; }
JavaScript
const ta = document.querySelector('textarea') function updateRowNumbering() { const num = ta.value.split("\n").length; const numbers = ta.parentNode.querySelector(".numbers"); numbers.innerHTML = Array(num).fill(`<span style="overflow: hidden"></span>`).join(""); // 行号更新后重新高亮当前行 highlightLineNumber(getCurrentLineNumber()); } ta.textContent = `I love Tanzania Nasila America Football JavaScript Chess Ang Probinsyano Startimes China` updateRowNumbering(); function getCurrentLineNumber() { const caretPosition = ta.selectionStart; const text = ta.value; const lines = text.split('\n'); let currentLine = 1; let accumulatedLength = 0; for (let i = 0; i < lines.length; i++) { accumulatedLength += lines[i].length + 1; // +1 是换行符的长度 if (caretPosition < accumulatedLength) { currentLine = i + 1; break; } // 处理光标在最后一行末尾的情况 if (i === lines.length - 1 && caretPosition === accumulatedLength - 1) { currentLine = i + 1; } } return currentLine; } function highlightLineNumber(lineNumber) { const numberSpans = document.querySelectorAll('.numbers span'); // 清除所有高亮 numberSpans.forEach(span => { span.style.backgroundColor = ''; }); // 高亮当前行,避免索引越界 if (lineNumber > 0 && lineNumber <= numberSpans.length) { numberSpans[lineNumber - 1].style.backgroundColor = 'gray'; } } // 绑定所有需要监听的事件 const textarea = document.querySelector('#textarea'); ['click', 'input', 'keydown', 'mouseup'].forEach(event => { textarea.addEventListener(event, () => { const currentLine = getCurrentLineNumber(); highlightLineNumber(currentLine); }); });
内容的提问来源于stack exchange,提问作者Abednego Nasila
相关产品推荐
相关产品推荐

