【问题标题】:How to stop window jumping when typing in autoresizing textarea输入自动调整大小的文本区域时如何停止窗口跳转
【发布时间】:2013-08-18 05:38:46
【问题描述】:

我正在使用this question 的公认答案来构建一个文本区域,该文本区域会随着文本溢出而垂直扩展:

<!DOCTYPE html>
<html>
<head>
<title>autoresizing textarea</title>
<style type="text/css">
textarea {
 border: 0 none white;
 overflow: hidden;
 padding: 0;
 outline: none;
 background-color: #D0D0D0;
 resize: none;
}
</style>
<script type="text/javascript">
var observe;
if (window.attachEvent) {
 observe = function (element, event, handler) {
  element.attachEvent('on'+event, handler);
 };
}
else {
 observe = function (element, event, handler) {
  element.addEventListener(event, handler, false);
 };
}
function init () {
 var text = document.getElementById('text');
 function resize () {
  text.style.height = 'auto';
  text.style.height = text.scrollHeight+'px';
 }
 /* 0-timeout to get the already changed text */
 function delayedResize () {
  window.setTimeout(resize, 0);
 }
 observe(text, 'change',  resize);
 observe(text, 'cut',     delayedResize);
 observe(text, 'paste',   delayedResize);
 observe(text, 'drop',    delayedResize);
 observe(text, 'keydown', delayedResize);

 text.focus();
 text.select();
 resize();
}
</script>
</head>
<body onload="init();">
<textarea rows="1" style="height:1em;" id="text"></textarea>
</body>
</html>

在 textarea 的大小比浏览器窗口长之前它运行良好。此时,每次按下一个键时,窗口的顶部都会跳到文本区域的顶部。你能帮我理解为什么以及如何解决它吗?

一个理想的解决方法是完全阻止页面移动。但是,如果将页面底部与文本区域的底部联系起来更容易,那也可以。

我在 Firefox 21.0 和 Chrome 28.0 中遇到了这个问题:http://jsfiddle.net/CbqFv/

【问题讨论】:

  • 我在 FF 中没有同样的问题,但在 Chrome 中确实可以看到。

标签: javascript textarea autoresize


【解决方案1】:

保存scrollLeftscrollTop的值,然后在调整textarea大小后恢复它们:

function resize () {
   var scrollLeft = window.pageXOffset ||
   (document.documentElement || document.body.parentNode || document.body).scrollLeft;

   var scrollTop  = window.pageYOffset ||
   (document.documentElement || document.body.parentNode || document.body).scrollTop;

   text.style.height = "auto";
   text.style.height = text.scrollHeight + 'px';

   window.scrollTo(scrollLeft, scrollTop);
}

JSFiddle:http://jsfiddle.net/losnir/nnkeH/1

【讨论】:

  • @losnir,除了在可滚动 div 的上下文中,您是否知道这样做的方法?我有一个在快速查看 div 中的文本区域,所以它的位置不是窗口的位置,而是 div 的位置。
【解决方案2】:

您应该将页面滚动到:滚动条位置 +(调整大小后的文本区域高度 - 调整大小之前的文本区域高度)

代码如下:

    function resize () {
      var scrollLeft = window.pageXOffset ||
      (document.documentElement || document.body.parentNode || document.body).scrollLeft;

      var scrollTop  = window.pageYOffset ||
      (document.documentElement || document.body.parentNode || document.body).scrollTop;

      var prevHeight = text.style.height.slice(0, -2);
      text.style.height = "auto";
      var nextHeight = text.scrollHeight;
      text.style.height = text.scrollHeight + 'px';
      window.scrollTo(scrollLeft, scrollTop + (nextHeight - prevHeight));
    }

或者您可以使用 jquery 来执行此操作(基于 this answer):

    $('body').on('keyup', 'textarea', function (e) {
      var scrollTop  = $(document).scrollTop();
      var prevHeight = $(this).height();
      $(this).css('height', 'auto');
      var nextHeight = this.scrollHeight;
      $(this).height(nextHeight);
      $(document).scrollTop(scrollTop + (nextHeight - prevHeight));
    });
    $( 'textarea' ).keyup();

【讨论】:

  • 除了在可滚动 div 的上下文中之外,您知道一种方法吗?我有一个在快速查看 div 中的文本区域,所以它的位置不是窗口的位置,而是 div 的位置。
【解决方案3】:

当文本区域位于可滚动的 div 中时,一种接受答案的方法:

function getScrollParent(node) {
    if (node == null) {
        return null;
    }

    if (node.scrollHeight > node.clientHeight) {
        return node;
    } else {
        return getScrollParent(node.parentNode);
    }
}

function resize(){
    // 'this' is the textarea
    const scrollParent = getScrollParent(this);
    const scrollTop = scrollParent ? scrollParent.scrollTop : null;
    const scrollLeft = scrollParent ? scrollParent.scrollLeft : null;

    this.style.height = "auto";
    this.style.height = this.scrollHeight + "px";

    if (scrollParent) {
        scrollParent.scrollTo(scrollLeft, scrollTop);
    }
};

【讨论】:

  • 或者你可以使用我接受的答案:stackoverflow.com/a/66070525/13231904
  • 我不得不将 this 更改为 this.parentNode 否则它一直将 textarea 获取为 scrollParent 并且什么也没发生
【解决方案4】:

我的回复基于接受的答案中的小提琴:height of textarea increases when value increased but does not reduce when value is decreased

这适用于页面加载和以任何方式更改文本(剪切、粘贴、键入等)时

$('textarea').on('keyup keydown', function () {
var $this = $(this);
var initialHeight = $this.height();

$this
    .height(initialHeight - 40)
    .height($this[0].scrollHeight + 20);}).trigger('keyup');

我获取初始高度的原因是 textarea 不必跳到 1 或任何其他静态数字来触发 scrollHeight 的值。 (据我了解,这是导致屏幕更改滚动的原因,因为文本框设置为该静态高度(通常为 1)然后扩展)我将 20 添加到 scrollHeight 的原因是因为有时 scrollHeight 会关闭 1 或 2px 并且文本看起来在底部聚集在一起。所以为了给它更多的空间,我个人添加了 20 个。

【讨论】:

    【解决方案5】:

    发现这是迄今为止最好的解决方案,结合了 Adam Beres-Deak 和 @losnir 的代码,得出了以下结果。

    目前为止最有用的:

    if(window.attachEvent){
        observe = function(element, event, handler){ element.attachEvent('on'+event, handler); };
    }else{
        observe = function(element, event, handler){ element.addEventListener(event, handler, false); };
    }
    function init(){
        var textAreas = [].slice.call(document.querySelectorAll('textarea[data-adaptheight]'));
        textAreas.forEach(function(el){
            function resize(){
                var scrollLeft = window.pageXOffset ||
                    (document.documentElement || document.body.parentNode || document.body).scrollLeft;
                var scrollTop = window.pageYOffset ||
                    (document.documentElement || document.body.parentNode || document.body).scrollTop;
                el.style.resize = "none";
                el.style.overflow = 'hidden';
                el.style.boxSizing = el.style.mozBoxSizing = 'border-box';
                el.style.height = "auto";
                el.style.height = el.scrollHeight + 'px';
                window.scrollTo(scrollLeft, scrollTop);
            }
            observe(el, 'input', resize);
            resize();
        });
    }
    init();
    <textarea data-adaptheight style="padding: 7px;width: 100%;display: block;" rows="1" cols="40" placeholder="Your input">
    </textarea>

    【讨论】:

      【解决方案6】:

      关于 losnir 的回答,在 Firefox Desktop (88) 中,window.pageXOffset 似乎返回一个非整数值,但 window.scrollTo() 将其舍入为整数值。因此,如果初始 window.pageXOffset 值的小数部分为 0.5 或更多,那么在每次更改文本时,文本区域框都会向下移动少量。其他浏览器可能会发生这种情况。解决方案是将滚动变量声明为四舍五入,然后在第一次更改文本时有一个小的偏移,之后所有的值都将是整数,并且不会发生进一步的偏移。这给出了:

      function resize () {
          var scrollLeft = Math.round(window.pageXOffset ||
                      (document.documentElement || document.body.parentNode || document.body).scrollLeft);
         var scrollTop  = Math.round(window.pageYOffset ||
                      (document.documentElement || document.body.parentNode || document.body).scrollTop);
      
         text.style.height = "auto";
         text.style.height = text.scrollHeight + 'px';
      
         window.scrollTo(scrollLeft, scrollTop);
      }
      

      【讨论】:

        猜你喜欢
        • 2013-03-29
        • 2013-03-24
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 1970-01-01
        • 2011-02-28
        • 1970-01-01
        相关资源
        最近更新 更多