如何将 textarea 的插入符号始终保持在视口内?

Posted

技术标签:

【中文标题】如何将 textarea 的插入符号始终保持在视口内?【英文标题】:How do I keep a textarea's caret always within the viewport? 【发布时间】:2012-10-15 00:33:17 【问题描述】:

我有一个用于编辑大量文本的文本区域很长的页面。通常,当您键入时,当插入符号接近文本区域的底部时,页面会自动滚动以使插入符号始终保持在视口内(Firefox 一次滚动一行,Chrome 会将插入符号滚动到视口)。

我的问题来自这样一个事实,即我正在根据用户键入的内容以编程方式更改文本区域的内容。在某些情况下,这涉及添加额外的内容,从而将插入符号推到视野之外。

只要用户点击一个键,自动滚动就会启动,插入符号会滚动到视图中——但不是之前,所以当用户键入时,他们会看不到插入符号。我曾希望我可以简单地触发 textarea 上的关键事件让浏览器自动滚动,但触发的事件并不能完全模拟用户行为,我也没有得到响应。

我现在能看到的唯一解决方案是尝试通过以下方式获取插入符号的 XY 坐标:

    查找插入符号的字符位置。 构建一个 div,在插入符号位置使用标记来镜像 textarea 的内容。 测量标记的位置。

有没有更简单的方法来做到这一点?

【问题讨论】:

可能相关:***.com/a/12738472/1615483 【参考方案1】:

我不想建议为一个问题添加整个库,但请考虑查看 CodeMirror。它为您处理所有这些事情,而且使用起来相当简单。

http://codemirror.net/

【讨论】:

【参考方案2】:

[之前的解决方案不兼容 Chrome (WebKit?)]

如果,一个 BIG if,额外的内容被附加到输入的末尾,下面的练习可能会提供解决方案:

<html>
  <head>
    <script>
      function btnGoOnClick(ctrl)
      
        //-- For this POC the text content is reset to 160 lines of dummy text -
        //----------------------------------------------------------------------

        ctrl.value = "";

        for (var i = 0; i < 160; ++i)
        
          ctrl.value += "dummy!\n";
        

        //-- Then the carret is set to the last position -----------------------
        //----------------------------------------------------------------------

        if (ctrl.createTextRange)
        
          //-- IE specific methods to move the carret to the last position

          var textRange = ctrl.createTextRange();
          textRange.moveStart("character", ctrl.value.length);
          textRange.moveEnd("character", 0);
          textRange.select();
        
        else
        
          //-- Mozilla and WebKit methods to move the carret

          ctrl.setSelectionRange(ctrl.value.length, ctrl.value.length);
        

        //-- For WebKit, the scroll bar has to be explicitly set ---------------
        //----------------------------------------------------------------------

        ctrl.scrollTop = ctrl.scrollHeight;

        //-- Almost there: make sure the control has fucos and is into view ----
        //----------------------------------------------------------------------

        ctrl.focus();
        ctrl.scrollIntoView(false);
      
    </script>
  </head>
  <body>
    <form name="form">
      <input type="button" name="btnGo" value="Go!" onClick="btnGoOnClick(document.form.text);" />
      <div style="height: 1000px"></div>
      <textarea name="text" rows="80"></textarea>
    </form>
  </body>
</html>

【讨论】:

我看到的是 scrollIntoView() 将视口滚动到 textarea 的顶部,但这与插入符号的位置没有任何关联(我的 textarea 的高度大于视口高度,因此插入符号仍然可以看不见)。 对不起,我的错!我对 Mozilla 和 IE 进行了测试,跳过了 Chrome (WebKit)。我设计了一个更广泛的、失败证明的解决方案,并将编辑我的帖子。请即使您已经满足了您的需求,也请评估一下,如果证明是正确的,请将我的帖子标记为有效。我(我们)需要这些学分:-)【参考方案3】:

由于您已经在 javascript 路径上,并且假设动态 textarea 高度会造成设计问题,您可以尝试按内容自动调整 textarea 的大小:

function resizeTextarea(textarea) 
  var lines = textarea.value.split('\n');
  var width = textarea.cols;
  var height = 1;
  for (var i = 0; i < lines.length; i++) 
    var linelength = lines[i].length;
    if (linelength >= width) 
      height += Math.ceil(linelength / width);
    
  
  height += lines.length;
  textarea.rows = height;

我知道这并不能回答您帖子中概述的细节,但它提供了一种适合您问题标题的替代方法。因此,即使它对您没有用,也可能对访问此问题的其他人有用。

我个人讨厌太小的文本区域,并且视情况而定,希望它们自动调整大小。

【讨论】:

感谢您的想法,我想这是解决不同问题的方法。在我的情况下,我已经使用 jquery-elastic 自动扩展了 textarea 的大小(尽管它的默认大小已经大于视口),我相信这与您提供的代码相同。

以上是关于如何将 textarea 的插入符号始终保持在视口内?的主要内容,如果未能解决你的问题,请参考以下文章

您如何以编程方式将 Flex TextArea 的插入符号移到末尾?

JavaFX:在进入 TextArea 时将插入符号/光标放在 TextArea 的末尾

如何使用 JavaScript 查找 INPUT 和 TEXTAREA 插入符号位置坐标?

如何将图形保持在主窗口的中心

获取 TextArea 中插入符号的 XY 位置

根据宽度和高度保持纵横比