如何使用JavaScript在textarea中实现退格以解决多行取消缩进异常问题
问题根源说明
- 退格符
\b无法实现预期效果:\b属于终端控制符,仅在命令行等特殊场景会被解析为退格操作,浏览器textarea会将其识别为普通不可见字符,渲染为你看到的方框,该方案完全不可行,直接放弃。 - 选中内容从制表符后开始时无法取消缩进:你当前仅截取了选中起止范围内的子串做拆分,若选中起点不在行首,拆分得到的行内容本身就不包含行首的
\t,自然匹配不到可删除的制表符。 - 全选缩进时selectionEnd偏移异常:你写死了固定的偏移值(
end + 3、end - 2),但不同选中范围下新增/删除的制表符数量不固定,固定偏移值必然会出现定位错误。
解决思路&修改后代码
核心逻辑调整:处理缩进前先将选中范围扩展到覆盖所有涉及行的完整行首、行尾,拿到完整行内容再做缩进修改,最后根据实际修改的制表符数量动态计算新的选中范围。
修改后JS代码
$(document).on('keydown', '#t_cont', function(e) { const keyCode = e.keyCode || e.which; let start = this.selectionStart; let end = this.selectionEnd; const val = $(this).val(); // 先将选中范围扩展到完整的行起止 let lineStart = val.lastIndexOf('\n', start - 1) + 1; let lineEnd = val.indexOf('\n', end); lineEnd = lineEnd === -1 ? val.length : lineEnd; const selectedContent = val.substring(lineStart, lineEnd); const lines = selectedContent.split('\n'); let tabChangeCount = 0; // 统计总共修改了多少个制表符,用于计算选中偏移 if (e.shiftKey && keyCode === 9) { // Shift+Tab 取消缩进 e.preventDefault(); const processedLines = lines.map(line => { if (line.startsWith('\t')) { tabChangeCount--; return line.substring(1); } return line; }); const newContent = processedLines.join('\n'); $(this).val(val.substring(0, lineStart) + newContent + val.substring(lineEnd)); // 计算新的选中范围 this.selectionStart = Math.max(start + tabChangeCount, lineStart); this.selectionEnd = Math.max(end + tabChangeCount, lineStart + newContent.length); } else if (keyCode === 9) { // Tab 缩进 e.preventDefault(); if (start === end) { // 无选中,直接插入制表符 $(this).val(val.substring(0, start) + '\t' + val.substring(end)); this.selectionStart = this.selectionEnd = start + 1; return; } // 多行选中,每行行首加制表符 const processedLines = lines.map(line => { tabChangeCount++; return '\t' + line; }); const newContent = processedLines.join('\n'); $(this).val(val.substring(0, lineStart) + newContent + val.substring(lineEnd)); // 计算新的选中范围 this.selectionStart = start + 1; this.selectionEnd = end + tabChangeCount; } });
其余代码无需修改
CSS和HTML部分可以沿用你原来的实现。
内容的提问来源于stack exchange,提问作者перевод и субтитр Петровы
相关产品推荐
相关产品推荐

