纯Javascript - 在多行文本区域中获取当前行的起始位置

时间:2018-01-14 04:22:36

标签: javascript html caret

我正在寻找纯粹的 javascript 答案,因为这反映了我的项目范围。 jQuery答案不会被标记为正确,但欢迎未来的问题搜索者。旁注:我对第三方图书馆也不感兴趣。

我试图在多行selectionStart中获取当前行的第一个位置(0)(当前基于textarea用户选择多于1行的机会),但将其转换为插入符号索引。

我尝试了什么?没什么好看的:

for ( i = 0; i < this.selectionStart; i++ ) {      
  if (this.value.substr(i,1).match(/\r?\n|\r/)) {
    lineStartIndx = i + 1
  }
}

当使用大量的行迭代textareas时,这被证明是昂贵的。我个人对此的使用不会在每次keydown执行,但是,我只是以它为例。是否有更好的方法,内置或以其他方式模仿这一结果?

我的完整例子:

&#13;
&#13;
var input = document.getElementById("ta");
  var output = document.getElementById("output");
  let pattern = /\r?\n|\r/;
  var lineNum, lineStartIndx;
 
  input.addEventListener("keydown", function(e) {
    taHandler(this);		
  })

  input.addEventListener("click", function(e) {
    taHandler(this);
  })

  function taHandler(elem) {

    lineNum = getLineNumForSelection(elem);

    let caretPos = elem.selectionStart;
    lineStartIndx = 0;

    for ( i = 0; i < caretPos; i++ ) {

      if (elem.value.substr(i,1).match(pattern)) {
        lineStartIndx = i + 1
      }
    }

    output.innerHTML = "Selection Start: " + caretPos + " Selection End: " + elem.selectionEnd + 
    " <br> Line Number: "  + lineNum.start + 
    "<br>Line Start Position: " + lineStartIndx;
  }

  function getLineNumForSelection(sel) {
    return {
      'start' : sel.value.substr(0, sel.selectionStart).split(pattern).length,
      'end' : sel.value.substr(0,sel.selectionEnd).split(pattern).length
    };
  }
&#13;
<textarea id="ta" rows="5" cols="50">
  Line one
    Line two
    Line three
  Line four  
</textarea>
<hr>
<div id="output"></div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

我的代码片段中的方法将内容分成行并使用.length属性而不是循环,因此它看起来更漂亮&#34;但是根据time complexity of javascript's .length可能不会更快,因为规范中没有任何内容可以防止浏览器执行缓慢。

关于代码的两个注意事项,我使用lineStartIndex,而不是没有e的lineStartIndx。由于lineNum是一个数组,我使用lineNumArray或selLineNums或更明显的东西,因为以num结尾的变量通常是整数。

&#13;
&#13;
var input = document.getElementById("ta");
  var output = document.getElementById("output");
  let pattern = /\r?\n|\r/;
  var lineNum, lineStartIndx;
 
  input.addEventListener("keydown", function(e) {
    taHandler(this);		
  })

  input.addEventListener("click", function(e) {
    taHandler(this);
  })

  function taHandler(elem) {

    lineNum = getLineNumForSelection(elem);

    let caretPos = elem.selectionStart;
    lineStartIndx = 0;

    // begin modified code
    let lines = elem.value.split(pattern),
        lineIndex = 0;
        
    while ( (lineIndex + 1 ) < lineNum.start ) {
        lineStartIndx += parseInt( lines[lineIndex].length ) + 1;
        lineIndex++;
    }
    // end modified code
  
    // begin replaced code
    for ( i = 0; i < caretPos; i++ ) {

      if (elem.value.substr(i,1).match(pattern)) {
        lineStartIndx = i + 1
      }
    }
    // end replaced code

    output.innerHTML = "Selection Start: " + caretPos + " Selection End: " + elem.selectionEnd + 
    " <br> Line Number: "  + lineNum.start + 
    "<br>Line Start Position: " + lineStartIndx;
  }

  function getLineNumForSelection(sel) {
    return {
      'start' : sel.value.substr(0, sel.selectionStart).split(pattern).length,
      'end' : sel.value.substr(0,sel.selectionEnd).split(pattern).length
    };
  }
&#13;
<textarea id="ta" rows="5" cols="50">
  Line one
    Line two
    Line three
  Line four  
</textarea>
<hr>
<div id="output"></div>
&#13;
&#13;
&#13;