找出“线”;文本区域中光标的(行)编号

发布于 2025-01-03 15:02:29 字数 2365 浏览 2 评论 0原文

我想找出并跟踪文本区域中光标的“行号”(行)。 (“更大的图景”是在每次创建/修改/选择新行时解析该行上的文本,当然,如果文本没有粘贴进去。这可以节省在设定的时间间隔不必要地解析整个文本。)

StackOverflow 上有几篇文章,但没有一个具体回答我的问题,大多数问题都是关于光标位置(以像素为单位)或在文本区域之外显示行号。

我的尝试如下,从第一行开始并且不离开文本区域时效果很好。当单击文本区域并在另一行返回该文本区域时,它会失败。将文本粘贴到其中时也会失败,因为起始行不是 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>

I would like to find out and keep track of the 'line number' (rows) of the cursor in a textarea. (The 'bigger picture' is to parse the text on the line every time a new line is created/modified/selected, if of course the text was not pasted in. This saves parsing the whole text un-necessarily at set intervals.)

There are a couple of posts on StackOverflow however none of them specifically answer my question, most questions are for cursor position in pixels or displaying lines numbers besides the textarea.

My attempt is below, it works fine when starting at line 1 and not leaving the textarea. It fails when clicking out of the textarea and back onto it on a different line. It also fails when pasting text into it because the starting line is not 1.

My JavaScript knowledge is pretty limited.

<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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

墨小墨 2025-01-10 15:02:29

您可能需要使用 selectionStart 来执行此操作:

function getLineNumber(textarea, indicator) {
    indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
}
<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea>
<div id="lineNo"></div>

当您使用鼠标更改光标位置时,这也适用。

You would want to use selectionStart to do this:

function getLineNumber(textarea, indicator) {
    indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
}
<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea>
<div id="lineNo"></div>

This works when you change the cursor position using the mouse as well.

<逆流佳人身旁 2025-01-10 15:02:29

由于自动换行,这很困难。计算存在的换行符数量是一件非常容易的事情,但是当新行是由于自动换行而产生时会发生什么?为了解决这个问题,创建一个镜像很有用(来源:github.com/jevin)。思路是这样的:

  1. 创建textarea的镜像
  2. 将textarea开头到光标处的内容发送到镜像
  3. 使用镜像的高度提取当前行

在 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();
});

This is tough because of word wrap. It's a very easy thing to count the number of line breaks present, but what happens when the new row is because of word wrap? To solve this problem, it's useful to create a mirror (credit: github.com/jevin). Here's the idea:

  1. Create a mirror of the textarea
  2. Send the content from the beginning of the textarea to the cursor to the mirror
  3. Use the height of the mirror to extract the current row

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();
});
街角卖回忆 2025-01-10 15:02:29

当我发现你可以获得光标的边界矩形时,我解决了这个问题,因此它是相对于父级的 y 坐标

const editorCords = document.querySelector('#editor').getClientRects()[0]
const cursorCords = window.getSelection()?.getRangeAt(0).getClientRects()[0]
    
if (editorCords && cursorCords) {
   const line = Math.floor((cursorCords.y - editorCords.y) / cursorCords.height)
   console.log(line)
}

I cracked this when I found out you could get the bounding rect of the cursor, and thus it's y coordinate relative to the parent

const editorCords = document.querySelector('#editor').getClientRects()[0]
const cursorCords = window.getSelection()?.getRangeAt(0).getClientRects()[0]
    
if (editorCords && cursorCords) {
   const line = Math.floor((cursorCords.y - editorCords.y) / cursorCords.height)
   console.log(line)
}
你怎么敢 2025-01-10 15:02:29

这对我有用:

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

This worked for me:

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
};

Inspired by colab's answer as a starting point, this includes the number of word wraps without having to introduce a mirror (as in bradbarbin's answer).

The trick is simply counting how many times the number of columns textarea.cols can divide the length of each segment between explicit line breaks \n.

Note: this starts counting at 1.

握住我的手 2025-01-10 15:02:29

使用 elem.selectionEnd 我可以获取光标的当前位置(即所选突出显示的末尾),然后使用 substrsplit("\n" ) 以在您开始使用 onkeyup 键入时获取行号。

信息显示如下:

Ln:3,Col:8,位置:18,Len:55

这些都指的是光标的当前位置:

  • Ln :行号
  • Col :列号(从at 1)
  • Pos :偏移位置
  • Len :整个文本的长度

我可以通过调用 onclick 来完成此操作该事件的 onkeyup()

<textarea id=d rows=7
  onkeyup="P=d.selectionEnd;V=d.value;A=V.substr(0,P).split`\n`;p.innerHTML=`Ln:${A.length}, Col:${A.pop().length+1}, Pos:${P}, Len:${V.length}`"
  onclick=this.onkeyup()
  style=width:100%></textarea>

<p id=p></p>

您还可以将此代码复制粘贴到地址栏中,并将其保存为书签以供以后使用:

data:text/html,<textarea id=d rows=7 onkeyup="P=d.selectionEnd;V=d.value;A=V.substr(0,P).split`\n`;p.innerHTML=`Ln:${A.length}, Col:${A.pop().length+1}, Pos:${P}, Len:${V.length}`" onclick=this.onkeyup() onkeypress=e=event;k=e.keyCode;(e.ctrlKey&&k==13)||k==10?f.srcdoc=d.value:0 style=width:100%></textarea> <p id=p></p>

我认为这是一个很好的起点,您想要创建自己的自定义文本编辑器来显示该信息。我以此代码为例制作了一个 小型 HTML 代码编辑器

Using elem.selectionEnd I could get the current position of your cursor (which is the end of your selected highlight) then used substr and split("\n") to get the line number when you start typing using onkeyup.

The information is displayed like this:

Ln:3, Col:8, Pos:18, Len:55

This all refers to the current position of your cursor:

  • Ln : Line number
  • Col : Column number (starts at 1)
  • Pos : Offset position
  • Len : Length of the entire text

I was able to do this onclick by calling onkeyup() on that event.

<textarea id=d rows=7
  onkeyup="P=d.selectionEnd;V=d.value;A=V.substr(0,P).split`\n`;p.innerHTML=`Ln:${A.length}, Col:${A.pop().length+1}, Pos:${P}, Len:${V.length}`"
  onclick=this.onkeyup()
  style=width:100%></textarea>

<p id=p></p>

You can also copy-paste this code into your address bar and save it as a bookmark to use later:

data:text/html,<textarea id=d rows=7 onkeyup="P=d.selectionEnd;V=d.value;A=V.substr(0,P).split`\n`;p.innerHTML=`Ln:${A.length}, Col:${A.pop().length+1}, Pos:${P}, Len:${V.length}`" onclick=this.onkeyup() onkeypress=e=event;k=e.keyCode;(e.ctrlKey&&k==13)||k==10?f.srcdoc=d.value:0 style=width:100%></textarea> <p id=p></p>

I think this is a good place to start of you wanted to create your own custom text editor that displays that information. I made a tiny HTML code editor with this code as an example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文