找出textarea中光标的“line”(行)编号

时间:2012-02-07 23:24:16

标签: javascript textarea

我想找出并跟踪textarea中光标的“行号”(行)。 (“更大的图片”是每次创建/修改/选择新行时解析行上的文本,如果当然没有粘贴文本。这样可以节省解析整个文本的时间间隔。)

StackOverflow上有几个帖子,但是没有一个帖子专门回答我的问题,大多数问题是光标位置(以像素为单位)或显示除textarea之外的行号。

我的尝试如下,从第1行开始并且不离开textarea时工作正常。单击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>

4 个答案:

答案 0 :(得分:32)

您可能希望使用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>

当您使用鼠标更改光标位置时也可以。

答案 1 :(得分:20)

由于自动换行,这很难。计算存在的换行数是一件非常容易的事情,但是当新行是由于自动换行时会发生什么?要解决此问题,创建镜像很有用(credit:github.com/jevin)。这是个主意:

  1. 创建textarea的镜像
  2. 将内容从textarea的开头发送到光标到镜像
  3. 使用镜像的高度来提取当前行
  4. 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, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;').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();
    });
    

答案 2 :(得分:2)

Jakub P. May和Andrew Li Sep的两条评论;表示这两个人不了解文本区域中一行的性质。

在文本区域中换行是为了能够阅读文本而无需横向滚动。视觉上将文字换行到视觉新行,不等于新行。

这是所有文本编辑器(包括Notepad ++,Notepad以及Microsoft Word和大多数文本编辑软件)中都具有的基本功能和预期功能。

让textarea或文本编辑器在文本换行时输入硬换行符将使从编码的角度确定行何时开始和结束变得困难。这将导致句子在中间而不是末尾被分解,这将使得很难在文本搜索中找到特定的句子,因为换行符将构成句子中的其他字符,从而导致预期的匹配失败。

软换行符不是换行符,因此,尽管具有视觉外观,但文本仍应保留在同一行。

答案 3 :(得分:0)

这对我有用:

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开始计数。