在文本区域中找出光标的“行”(行)号
Posted
技术标签:
【中文标题】在文本区域中找出光标的“行”(行)号【英文标题】:Find out the 'line' (row) number of the cursor in a textarea 【发布时间】:2012-02-29 10:25:21 【问题描述】:我想找出并跟踪文本区域中光标的“行号”(行)。 (“更大的图景”是每次创建/修改/选择新行时解析行上的文本,当然如果没有粘贴文本。这样可以节省不必要地以设定的时间间隔解析整个文本。)
*** 上有几篇文章,但没有一篇专门回答我的问题,大多数问题都是关于光标位置(以像素为单位)或在文本区域之外显示行号。
我的尝试如下,从第 1 行开始并且不离开 textarea 时效果很好。单击文本区域并在另一行返回时失败。粘贴文本时也会失败,因为起始行不是 1。
我的 javascript 知识非常有限。
<html>
<head>
<title>DEVBug</title>
<script type="text/javascript">
var total_lines = 1; // total lines
var current_line = 1; // current line
var old_line_count;
// main editor function
function code(e)
// declare some needed vars
var keypress_code = e.keyCode; // key press
var editor = document.getElementById('editor'); // the editor textarea
var source_code = editor.value; // contents of the editor
// work out how many lines we have used in total
var lines = source_code.split("\n");
var total_lines = lines.length;
// do stuff on key presses
if (keypress_code == '13') // Enter
current_line += 1;
else if (keypress_code == '8') // Backspace
if (old_line_count > total_lines) current_line -= 1;
else if (keypress_code == '38') // Up
if (total_lines > 1 && current_line > 1) current_line -= 1;
else if (keypress_code == '40') // Down
if (total_lines > 1 && current_line < total_lines) current_line += 1;
else
//document.getElementById('keycodes').innerHTML += keypress_code;
// for some reason chrome doesn't enter a newline char on enter
// you have to press enter and then an additional key for \n to appear
// making the total_lines counter lag.
if (total_lines < current_line) total_lines += 1 ;
// putput the data
document.getElementById('total_lines').innerHTML = "Total lines: " + total_lines;
document.getElementById('current_line').innerHTML = "Current line: " + current_line;
// save the old line count for comparison on next run
old_line_count = total_lines;
</script>
</head>
<body>
<textarea id="editor" rows="30" cols="100" value="" onkeydown="code(event)"></textarea>
<div id="total_lines"></div>
<div id="current_line"></div>
</body>
</html>
【问题讨论】:
【参考方案1】:您可能希望使用selectionStart
来执行此操作。
<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea>
<div id="lineNo"></div>
<script>
function getLineNumber(textarea, indicator)
indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
</script>
这在您使用鼠标更改光标位置时也有效。
【讨论】:
如果文本区域中有软换行符,此解决方案将不起作用。示例:创建一个有 10 列的文本区域,在其中放入几个单词,以便文本溢出到 2-3 行 - 但不要在其中添加换行符。上面的代码将始终返回 1,因为 textarea 中没有“\n”字符 - 但用户实际上看到的行不止 1 行。这就是 TEXTAREA 的真正困难......我真的很惊讶在现代浏览器中没有任何标准 API...... 这不适用于所有情况。如果你输入没有换行符的文本,上面的函数总是返回 1。但它可能是 2 或更多。【参考方案2】:由于自动换行,这很困难。计算出现的换行数是一件非常容易的事情,但是当新行是因为自动换行时会发生什么?为了解决这个问题,创建一个镜像很有用(来源:github.com/jevin)。想法是这样的:
-
创建文本区域的镜像
将textarea开头到光标处的内容发送到镜像
使用镜像高度提取当前行
On JSFiddle
jQuery.fn.trackRows = function()
return this.each(function()
var ininitalHeight, currentRow, firstIteration = true;
var createMirror = function(textarea)
jQuery(textarea).after('<div class="autogrow-textarea-mirror"></div>');
return jQuery(textarea).next('.autogrow-textarea-mirror')[0];
var sendContentToMirror = function (textarea)
mirror.innerHTML = String(textarea.value.substring(0,textarea.selectionStart-1)).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br />') + '.<br/>.';
calculateRowNumber();
var growTextarea = function ()
sendContentToMirror(this);
var calculateRowNumber = function ()
if(firstIteration)
ininitalHeight = $(mirror).height();
currentHeight = ininitalHeight;
firstIteration = false;
else
currentHeight = $(mirror).height();
// Assume that textarea.rows = 2 initially
currentRow = currentHeight/(ininitalHeight/2) - 1;
//remove tracker in production
$('.tracker').html('Current row: ' + currentRow);
// Create a mirror
var mirror = createMirror(this);
// Style the mirror
mirror.style.display = 'none';
mirror.style.wordWrap = 'break-word';
mirror.style.whiteSpace = 'normal';
mirror.style.padding = jQuery(this).css('padding');
mirror.style.width = jQuery(this).css('width');
mirror.style.fontFamily = jQuery(this).css('font-family');
mirror.style.fontSize = jQuery(this).css('font-size');
mirror.style.lineHeight = jQuery(this).css('line-height');
// Style the textarea
this.style.overflow = "hidden";
this.style.minHeight = this.rows+"em";
var ininitalHeight = $(mirror).height();
// Bind the textarea's event
this.onkeyup = growTextarea;
// Fire the event for text already present
// sendContentToMirror(this);
);
;
$(function()
$('textarea').trackRows();
);
【讨论】:
这应该是公认的答案。我没有测试过代码,但它至少尝试了一个处理软换行符的工作解决方案。 样式是解决方案的强制性部分吗?我在没有 CSS 的情况下实现了这一点,并将我的 textarea wrap 属性设置为“off”。如果我随后在 textarea 中键入文本,使其超出 textarea 的边缘(强制显示水平滚动条),即使我没有创建新行,行号也会报告为增加。 不幸的是,这也有未处理的极端情况。例如:在 10 列的文本区域中,如果您在第一行按ctrl+right
- 它会将光标移动到第一行末尾的 10 (textarea.selectionStart=10)。但是,如果您尝试通过right
或left
将光标移动到相同的 textarea.selectionStart=10 位置 - 光标明显会位于第二行的开头。【参考方案3】:
这对我有用:
function getLineNumber(textarea)
return textarea.value.substr(0, textarea.selectionStart) // get the substring of the textarea's value up to the cursor position
.split("\n") // split on explicit line breaks
.map((line) => 1 + Math.floor(line.length / textarea.cols)) // count the number of line wraps for each split and add 1 for the explicit line break
.reduce((a, b) => a + b, 0); // add all of these together
;
以 colab 的回答为起点,这包括无需引入镜像的自动换行次数(如 bradbarbin 的回答)。
诀窍是简单地计算列数textarea.cols
可以在显式换行符\n
之间划分每个段的长度的次数。
注意:这从1
开始计数。
【讨论】:
很遗憾,这不起作用,因为在执行软换行之前并非所有行都达到了完整的列数。以上是关于在文本区域中找出光标的“行”(行)号的主要内容,如果未能解决你的问题,请参考以下文章