插入符号位于textarea的第一行吗?在最后一行?

时间:2014-07-07 07:38:26

标签: javascript jquery html dom textarea

如果textarea具有不固定宽度的字体,我想在密钥上知道插入符号(由element.selectionEnd给出)是在文本的第一行还是最后一行。

Enter image description here

为了避免错误的答案,以下是一些工作的解决方案:

  • 分割\n:句子可以分为两行,因为它对于textarea的宽度来说太长了。
  • 测量插入符号之前的文本(例如,将文本复制到具有相同样式的div并测量跨度的高度):插入符号之后的某些字符可能会改变包装点(通常在单词之间)。

这里是测试的小提琴并消除了一些歧义(是的,它是textarea元素,它不仅仅是一行等等):{{3 }}

注意:

  • 我不关心Internet Explorer 9或移动浏览器。
  • 我需要一个可靠的解决方案,为插入符号的所有位置工作。
  • 有许多棘手的细节使大多数想法在实践中无法使用,请在回答之前建立一个工作小提琴。

5 个答案:

答案 0 :(得分:4)

目前最好的解决方案:

  • 创建一个具有两个跨度的临时div,并使CSS样式模仿(font,wordwrapping,scrollbars)textarea的包装行为。
  • 使用插入符号前的文本填充第一个范围。
  • 使用插入符号后面的文本填充第二个范围。
  • 使用跨度的offset.top和元素高度来了解我们是在第一行还是在最后一行。

我可以看到有效吗?

我制作了一个小提琴,使其显而易见:http://jsbin.com/qifezupu/31/edit

如何使用

我制作了一个jQuery插件:https://github.com/Canop/taliner.js

以下是相关的演示页面:http://dystroy.org/demos/taliner/demo.html

代码:

$.fn.taliner = function(){

    var $t = this,
        $d = $('<div>').appendTo('body'),
        $s1 = $('<span>').text('a').appendTo($d),
        $s2 = $('<span>').appendTo($d),
        lh =  $s1.height();

    $d.css({
        width: $t.width(),
        height: $t.height(),
        font: $t.css('font'),
        fontFamily: $t.css('fontFamily'), // for FF/linux
        fontSize: $t.css('fontSize'),
        whiteSpace : 'pre-wrap',
        wordWrap : 'break-word',
        overflowY: 'auto',
        position: 'fixed',
        bottom: 0,
        left: 0,
        padding: 0,
        zIndex: 666
    });

    var lh = $s1.height(),
        input = this[0],
        se = input.selectionEnd,
        v = input.value,
        res = {};

    $s1.text(v);
    res.linesNumber = $s1.height()/lh|0;

    $s1.text(v.slice(0, se));
    $s2.text(v.slice(se));
    res.caretOnFirstLine = input.selectionEnd===0
        || ($s1.height()<=lh && $s1.offset().top===$s2.offset().top);
    res.caretOnLastLine = $s2.height()===lh;

    $d.remove();
    return res;
}

它真的有效吗?

还有一个问题。我们在JavaScript中获得的关于插入位置的唯一信息是element.selectionEnd。这非常糟糕。

以下是两行textarea上可能的插入符号位置:

| A | B | C |
| D | E |

正如您所看到的,插入符号位置可能比字符间位置更多。更具体地说,在C和D之间有两个不同的插入位置,但DOM没有提供任何区分它们的方法。

这意味着有时,如果您单击行尾的右侧,库将无法判断它是行的结尾还是下一行的开头。

答案 1 :(得分:2)

有几种获得textarea内插入位置(以像素为单位)的方法:
Offset possition of the caret in a textarea in pixels

小心,他们可能会遇到不同浏览器的问题 您可以设置以后用于获取插入位置的预定义线高或字体大小。

我没有测试任何方法,但让我们假设用于获取插入位置的函数(以像素为单位)返回相对于插入符底部的 y 组件。
您指定的行高为15像素 假设方法返回(20,45)。当前行= y / 15 = 45/15 = 3

JS小提琴演示如何根据Dan的解决方案来完成它:
Current line from caret coordinates

我添加了显示当前行的范围。遗憾的是,我对Chrome的测试显示这并非100%准确:当您使用鼠标选择第三行时,它表示您在第4行。

Line:
<span id="line">0</span>

更新功能结束时(在HTML部分中),我添加了以下行:

//24 is the top padding of the textarea
//16 is the line-height
line.innerText = (coordinates.top - 24) / 16;

答案 2 :(得分:2)

基于@Flater所说的关于增加文本宽度的另一个解决方案。这个想法(总结)是:

  1. 获取textarea的宽度
  2. 在光标位置之前获取文字并计算其宽度
  3. 光标位置后获取文字并计算其宽度
  4. 如果之前的文字&gt;文本区域的宽度或不包含换行符(如果第一行的文字较少),第一行的光标
  5. 如果文字后面> <文字区域的宽度或不包含换行符,则光标不在最后一行
  6. 代码:

    $('#t').keyup(function(e){
      first_line="true";
      last_line="true";
      text = $(this).val();
      width = $(this).width();
      var cursorPosition = $(this).prop("selectionStart");
      txtBeforeCaret = text.substring(0, cursorPosition);
      txtAfterCaret = text.substring(cursorPosition);
      widthBefore = $('#holder').text(txtBeforeCaret).width();
      widthAfter = $('#holder').text(txtAfterCaret).width();
      match1 = txtBeforeCaret.match(/\n/);
      if(txtAfterCaret!==null){match2=txtAfterCaret.match(/\n/g);}
      if(widthBefore>width || match1){first_line="false";}
      if(widthAfter>width || (match2!==null && match2.length)) {last_line="false";}
      $('#f').html(first_line);
      $('#l').html(last_line);
    });
    

    #holder div创建并隐藏(以查找文字宽度)。

    <强> DEMO

答案 3 :(得分:1)

您可以通过将文本放入div并获得该div的宽度来测量一段文本的长度。

简而言之,请看一下jsFiddle。每次更改文本框中的文本时,都会收到文本宽度的警报。

所以我建议你做以下事情:

  • 找到textarea内容的第一行和最后一行。接下来的步骤适用于任何一行。
  • 要查看由于textarea的宽度而导致线条是否被分解,请使用我建议的片段检查文本宽度是否大于textarea的宽度。
  • 如果它更长,您可以迭代地开始检查线的子串。如果你找到一个与你的textarea宽度相匹配的,你可以非常肯定这是换行符的位置。

我不确定您想采取什么行动,但您可以使用此方法来估算您的插入符号的位置。 虽然可能不是像素完美,因为div宽度与文字宽度略有不同。

以下是衡量文字宽度的代码段:

$(document).ready(function() {

    $("#txtbox").keyup(function() {
        var the_Text = $("#txtbox").val();

        var width = $("#testdiv").text(the_Text).width();

        alert("The text width is : " + width + " px");
    });

});

$("#testdiv")是页面上隐藏的div。没什么好看的,唯一使用的CSS就是确保用户看不到它。

答案 4 :(得分:0)

这是一个使用这个jQuery插件(https://github.com/Codecademy/textarea-helper)来获取插入位置的小提琴(y位置是你需要的):http://jsbin.com/qifezupu/11/edit

不幸的是,正如您将看到的那样,需要进行一些调整。这只是一个想法。