如何使用 Prototype 自动调整文本区域的大小?

IT技术 javascript html css textarea prototypejs
2021-01-16 22:07:07

我目前正在为我工​​作的公司开发内部销售应用程序,我有一个表单,允许用户更改送货地址。

现在我认为它看起来会更好,如果我用于主要地址详细信息的 textarea 只会占用其中的文本区域,并在文本更改时自动调整大小。

这是当前的屏幕截图。

ISO地址

有任何想法吗?


@克里斯

一个很好的观点,但我有理由希望调整它的大小。我希望它占用的区域是其中包含的信息的区域。正如你在屏幕截图中看到的,如果我有一个固定的 textarea,它会占用相当多的垂直空间。

我可以减少字体,但我需要地址大且可读。现在我可以减少文本区域的大小,但是我遇到了地址行需要 3 或 4(一个需要 5)行的人的问题。需要让用户使用滚动条是一个主要的禁忌。

我想我应该更具体一点。我在垂直调整大小之后,宽度并不重要。唯一发生的问题是,当窗口宽度太小时(如您在屏幕截图中所见),ISO 编号(大的“1”)会被推到地址下方。

这不是噱头;这是关于拥有一个用户可以编辑的文本字段,该字段不会占用不必要的空间,但会显示其中的所有文本。

虽然如果有人想出另一种方法来解决这个问题,我也愿意接受。


我稍微修改了代码,因为它表现得有点奇怪。我将其更改为在 keyup 时激活,因为它不会考虑刚刚输入的字符。

resizeIt = function() {
  var str = $('iso_address').value;
  var cols = $('iso_address').cols;
  var linecount = 0;

  $A(str.split("\n")).each(function(l) {
    linecount += 1 + Math.floor(l.length / cols); // Take into account long lines
  })

  $('iso_address').rows = linecount;
};
6个回答

Facebook 做到了,当你在人们的墙上写字时,但只能垂直调整大小。

由于自动换行、长行等,水平调整大小让我觉得一团糟,但垂直调整大小似乎非常安全和漂亮。

我认识的所有使用 Facebook 的新手都没有提到任何关于它的内容或感到困惑。我会用这个作为轶事证据说“继续,实施它”。

一些 JavaScript 代码可以使用Prototype(因为这是我熟悉的):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script language="javascript">
            google.load('prototype', '1.6.0.2');
        </script>
    </head>

    <body>
        <textarea id="text-area" rows="1" cols="50"></textarea>

        <script type="text/javascript" language="javascript">
            resizeIt = function() {
              var str = $('text-area').value;
              var cols = $('text-area').cols;

              var linecount = 0;
              $A(str.split("\n")).each( function(l) {
                  linecount += Math.ceil( l.length / cols ); // Take into account long lines
              })
              $('text-area').rows = linecount + 1;
            };

            // You could attach to keyUp, etc. if keydown doesn't work
            Event.observe('text-area', 'keydown', resizeIt );

            resizeIt(); //Initial on load
        </script>
    </body>
</html>

PS:很明显,这段 JavaScript 代码很幼稚,没有经过很好的测试,你可能不想在有小说的文本框上使用它,但你已经大致了解了。

这假设浏览器在任何字符处中断,这是不正确的。试穿一下<textarea cols='5'>0 12345 12345 0</textarea>(我写了一个几乎相同的实现,直到使用它一个月后才发现它。)它也因空行而失败。
2021-03-22 22:07:07
$A(str.split("\n")) 中的反斜杠需要另一个。(由于某种原因,我对上述答案的编辑没有存活下来。)
2021-03-30 22:07:07
有没有针对此的 JQuery 版本?
2021-04-03 22:07:07

其中一些答案的一种改进是让 CSS 做更多的工作。

基本路线似乎是:

  1. 创建一个容器元素来保存textarea和隐藏div
  2. 使用JavaScript,以保持textarea“与同步的硫含量divS”
  3. 让浏览器做计算那个div高度的工作
  4. 因为浏览器处理隐藏的渲染/调整大小div,我们避免显式设置textarea的高度。

document.addEventListener('DOMContentLoaded', () => {
    textArea.addEventListener('change', autosize, false)
    textArea.addEventListener('keydown', autosize, false)
    textArea.addEventListener('keyup', autosize, false)
    autosize()
}, false)

function autosize() {
    // Copy textarea contents to div browser will calculate correct height
    // of copy, which will make overall container taller, which will make
    // textarea taller.
    textCopy.innerHTML = textArea.value.replace(/\n/g, '<br/>')
}
html, body, textarea {
    font-family: sans-serif;
    font-size: 14px;
}

.textarea-container {
    position: relative;
}

.textarea-container > div, .textarea-container > textarea {
    word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
    box-sizing: border-box;
    padding: 2px;
    width: 100%;
}

.textarea-container > textarea {
    overflow: hidden;
    position: absolute;
    height: 100%;
}

.textarea-container > div {
    padding-bottom: 1.5em; /* A bit more than one additional line of text. */ 
    visibility: hidden;
}
<div class="textarea-container">
    <textarea id="textArea"></textarea>
    <div id="textCopy"></div>
</div>

@unwitting 强烈呼吁添加“ ” 为了摆脱将第一个字母添加到新行时突然增加的大小 - 对我来说没有这个就坏了 - 这应该添加到答案中!
2021-03-14 22:07:07
将 textCopy 设置为 hidden 仍然允许隐藏的 div 占用标记中的空间,因此随着 textCopy 内容变大,您最终将获得沿页面整个长度的滚动条...
2021-03-19 22:07:07
对此的另一个很好的调整;var text = $("#textArea").val().replace(/\n/g, '<br/>') + '&nbsp;';确保在从 textarea 末尾的空行到非空行时不会出现生涩的行为,因为隐藏的 div 确保换行到 nbsp。
2021-03-22 22:07:07
我大胆地将这个解决方案作为独立的、易于使用的 jQuery 插件来实现,不需要任何标记或样式。xion.io/jQuery.xarea以防有人可以使用它:)
2021-03-29 22:07:07
这是一个很棒的解决方案!唯一需要注意的是,不支持 box-sizing (IE<7) 的浏览器将无法正确计算宽度,因此您将失去一些准确性,但如果您在最后留下一行的空间,你应该还好。绝对喜欢它的简单性。
2021-04-03 22:07:07

这是另一种自动调整文本区域大小的技术。

  • 使用像素高度而不是行高:如果使用比例字体,则更准确地处理换行。
  • 接受 ID 或元素作为输入
  • 接受一个可选的最大高度参数 - 如果您不想让文本区域增长超过特定大小(将其全部显示在屏幕上,避免破坏布局等),则很有用
  • 在 Firefox 3 和Internet Explorer 6上测试

代码:( 普通的 JavaScript)

function FitToContent(id, maxHeight)
{
   var text = id && id.style ? id : document.getElementById(id);
   if (!text)
      return;

   /* Accounts for rows being deleted, pixel value may need adjusting */
   if (text.clientHeight == text.scrollHeight) {
      text.style.height = "30px";
   }

   var adjustedHeight = text.clientHeight;
   if (!maxHeight || maxHeight > adjustedHeight)
   {
      adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
      if (maxHeight)
         adjustedHeight = Math.min(maxHeight, adjustedHeight);
      if (adjustedHeight > text.clientHeight)
         text.style.height = adjustedHeight + "px";
   }
}

演示:( 使用 jQuery,目标是我现在正在输入的文本区域 - 如果您安装了Firebug请将两个示例粘贴到控制台并在此页面上进行测试)

$("#post-text").keyup(function()
{
   FitToContent(this, document.documentElement.clientHeight)
});
@Jason:当框中的文本没有填充它clientHeight并且scrollHeight相等时,如果您希望 textarea 缩小和增长,则不能使用此方法。
2021-03-19 22:07:07
@SMB - 这可能不会太难实现,只需添加另一个条件
2021-04-02 22:07:07
要简单地缩小到,您只需要在第 6 行之前添加以下代码: if (text.clientHeight == text.scrollHeight) text.style.height = "20px";
2021-04-05 22:07:07

可能是最短的解决方案:

jQuery(document).ready(function(){
    jQuery("#textArea").on("keydown keyup", function(){
        this.style.height = "1px";
        this.style.height = (this.scrollHeight) + "px"; 
    });
});

这样你就不需要任何隐藏的 div 或类似的东西。

注意:您可能需要this.style.height = (this.scrollHeight) + "px";根据您设置 textarea 的样式(行高、填充和那种东西)来玩

如果您不介意滚动条闪烁,这是最佳解决方案。
2021-03-14 22:07:07
将 textarea 溢出属性设置为“隐藏”以避免滚动条闪烁。
2021-03-14 22:07:07
keyup可能就足够了,但我不确定。我很高兴我想通了,我停止尝试其他任何事情。
2021-03-19 22:07:07
我仍在尝试了解您为什么添加 this.style.height = "1px"; 或 this.style.height = "auto"; 前。我知道,如果我们不添加这一行,当我们删除内容时,textarea 不会调整大小。有人能解释一下吗?
2021-03-24 22:07:07
仅捕获 keyup 事件就足够了。你不这么认为吗?
2021-03-30 22:07:07

是调整文本区域大小原型版本,它不依赖于文本区域中的列数。这是一种卓越的技术,因为它允许您通过 CSS 控制文本区域以及具有可变宽度的文本区域。此外,此版本显示剩余字符数。虽然没有要求,但它是一个非常有用的功能,如果不需要,可以轻松删除。

//inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
if (window.Widget == undefined) window.Widget = {}; 

Widget.Textarea = Class.create({
  initialize: function(textarea, options)
  {
    this.textarea = $(textarea);
    this.options = $H({
      'min_height' : 30,
      'max_length' : 400
    }).update(options);

    this.textarea.observe('keyup', this.refresh.bind(this));

    this._shadow = new Element('div').setStyle({
      lineHeight : this.textarea.getStyle('lineHeight'),
      fontSize : this.textarea.getStyle('fontSize'),
      fontFamily : this.textarea.getStyle('fontFamily'),
      position : 'absolute',
      top: '-10000px',
      left: '-10000px',
      width: this.textarea.getWidth() + 'px'
    });
    this.textarea.insert({ after: this._shadow });

    this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
    this.textarea.insert({after: this._remainingCharacters});  
    this.refresh();  
  },

  refresh: function()
  { 
    this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
    this.textarea.setStyle({
      height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
    });

    var remaining = this.options.get('max_length') - $F(this.textarea).length;
    this._remainingCharacters.update(Math.abs(remaining)  + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
  }
});

通过调用创建小部件new Widget.Textarea('element_id')默认选项可以通过将它们作为对象传递来覆盖,例如new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). 如果要为页面上的所有文本区域创建它,请执行以下操作:

Event.observe(window, 'load', function() {
  $$('textarea').each(function(textarea) {
    new Widget.Textarea(textarea);
  });   
});