2012-02-07 65 views
15

我想找出並跟蹤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> 
+1

通過線,你的意思是排?說到文字時,欄和行不一樣。當使用非等寬字體時,沒有列。 – Anurag 2012-02-07 23:35:45

+0

對不起,是的,我的意思是排。我會更新我原來的帖子。 – ethicalhack3r 2012-02-07 23:38:21

回答

23

你會想要使用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> 

這也適用於使用鼠標更改光標位置。

+0

WOW。不能要求更好的解決方案!清潔和完美的作品!非常感謝你! – ethicalhack3r 2012-02-07 23:58:18

+0

不客氣:) – caleb 2012-02-08 00:06:38

+18

如果textarea中有軟線斷點,此解決方案將不起作用。 例如:製作一個帶10列的textarea,在其中放入幾個字,以便文本溢出到2-3行 - 但不要在其中添加換行符。上面的代碼將始終返回1,因爲textarea中沒有「\ n」字符 - 但用戶實際上看到的不止一行。 這是TEXTAREA的真正困難......我真的很驚訝現代瀏覽器中沒有任何標準的API ...... – 2012-05-16 23:50:06

16

由於單詞換行,這很困難。計算當前換行符的數量是一件非常容易的事情,但是當新行由於換行時會發生什麼?爲了解決這個問題,創建一個鏡像是很有用的(信用:github.com/jevin)。這裏的想法:

  1. 創建textarea的
  2. 的鏡發送來自textarea的開始時的內容,將光標到鏡像
  3. 使用鏡子的高度來提取當前行

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

這應該是被接受的答案。我沒有測試代碼,但它至少嘗試了一個處理軟線斷點的工作解決方案。 – ryandlf 2015-08-19 03:17:26

+0

造型是解決方案的強制性部分嗎?我在沒有CSS的情況下實現了這個功能,並將我的textarea wrap屬性設置爲'off'。如果我然後在textarea中鍵入文本,使其運行離開textarea的邊緣(迫使水平滾動條出現),即使我沒有創建新行,行號報告也會增加。 – youcantryreachingme 2018-02-22 01:13:12