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

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

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

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

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

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

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

【问题讨论】:

标签: javascript html textarea


【解决方案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 的大小(尽管它的默认大小已经大于视口),我相信这与您提供的代码相同。
    猜你喜欢
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 2010-10-15
    • 2016-09-15
    相关资源
    最近更新 更多