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


121

我目前正在为所工作的公司开发内部销售应用程序,并且我有一张表格可以让用户更改收货地址。

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

这是当前的屏幕截图。

ISO地址

有任何想法吗?


@克里斯

很好,但是我有理由要调整大小。我希望占用的区域是其中包含的信息的区域。从屏幕快照中可以看到,如果我有固定的textarea,它将占用相当大的垂直空间。

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

我想我应该更具体一些。我需要垂直调整大小,宽度也没关系。唯一发生的问题是,当窗口宽度太小时(如您在屏幕截图中看到的),ISO编号(大的“ 1”)被推到地址下方。

这不是要有个花哨的东西。这是关于用户可以编辑的文本字段,它不会占用不必要的空间,但会显示其中的所有文本。

尽管如果有人想出另一种方法来解决问题,我也很乐意。


我对代码进行了一些修改,因为它的行为有些奇怪。我将其更改为在键入时激活,因为它不会考虑刚刚键入的字符。

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;
};

您能否创建一个演示站点,以便我们在工作中看到它?
伊纳尔·奥拉夫森(EinarÓlafsson)2012年

3
这个插件看起来不错jacklmoore.com/autosize
Gaurav Shah

是否有JQuery版本?如何在JQuery中访问colA和TextArea的行?
Zach

几乎相同,但有明确的要求,当删除文本时,该
值应变

Answers:


75

当您在人们的墙上写字时,Facebook会这样做,但只能垂直调整大小。

由于自动换行,长行等原因,水平调整大小令我感到混乱,但是垂直调整大小似乎非常安全且不错。

我认识的所有使用Facebook的新手都从未提及或困惑过。我会将其用作传闻,说“继续前进,实施它”。

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

<!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代码非常幼稚且未经良好测试,您可能不希望在带有小说的文本框中使用它,但您已掌握了总体思路。


2
假定浏览器在任何字符处中断,这是不正确的。试穿一下<textarea cols='5'>0 12345 12345 0</textarea>。(我编写了几乎相同的实现,直到使用了一个月后才抓到它。)对于空白行,它也失败。
st-boost

是否有为此的JQuery版本?
emeraldhieu

$ A(str.split(“ \ n”))中的反斜杠需要另一个。(我对以上答案的编辑由于某种原因未能幸存。)
gherson

67

其中一些答案的一种改进是让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>


5
这是一个很棒的解决方案!唯一需要注意的是,不支持框大小调整(IE <7)的浏览器将无法正确计算宽度,因此会损失一些精度,但是如果最后要保留一行的空间,你应该还可以 绝对喜欢它的简单性。
Antonio Salazar Cardozo

4
我自由地将这种解决方案实现为独立的,易于使用的jQuery插件,不需要标记或样式。xion.io/jQuery.xarea,以防有人使用它:)
Xion

2
将textCopy设置为hidden仍然允许隐藏的div在标记中占据空间,因此,随着textCopy内容变大,您最终将在页面的整个长度上得到一个滚动条...
topwik 2013年

1
另一个不错的调整;var text = $("#textArea").val().replace(/\n/g, '<br/>') + '&nbsp;';确保从textarea末尾的空新行转到非空行时不会出现生涩的行为,因为隐藏的div可以确保换行到nbsp。

1
@取消添加“&nbsp;”的电话 为了消除在将第一个字母添加到新行时字体大小突然增加的情况-对我来说,如果没有此行,它是不完整的-应该将其添加到答案中!
davnicwil

40

这是另一种用于自动化文本区域的技术。

  • 使用像素高度而不是线条高度:如果使用比例字体,则更精确地处理换行。
  • 接受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)
});

@SMB-可能不太难实现,只需添加另一个条件
Jason 2010年

@Jason:当框中的文本没有填充clientHeightscrollHeight相等时,因此如果您希望文本区域缩小和增长,则不能使用此方法。
布兰特·鲍比

为了简单地缩小,您只需要在第6行之前添加以下代码:if (text.clientHeight == text.scrollHeight) text.style.height = "20px";
Gapipro,2011年

14

可能是最短的解决方案:

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";根据文本区域的样式(行高,填充和类似内容)进行操作。


如果您不介意滚动条闪烁,则为最佳解决方案。
cfillol

仅捕获keyup事件就足够了。你不这样认为吗
cfillol

2
将textarea溢出属性设置为“隐藏”,以避免滚动条闪烁。
cfillol

keyup可能就足够了,但我不确定。我很高兴自己发现了这一点,以至于我停止尝试其他任何事情。
爱德华·卢卡

我仍在尝试学习为什么要添加this.style.height =“ 1px”; 或this.style.height =“ auto”; 之前。我知道,如果不添加此行,则删除内容时textarea不会调整大小。有人可以解释吗?
Balasubramani M,

8

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

//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);
  });   
});

7

这是一个解决方案JQuery

$(document).ready(function() {
    var $abc = $("#abc");
    $abc.css("height", $abc.attr("scrollHeight"));
})

abc是一个teaxtarea


5

检查以下链接:http : //james.padolsey.com/javascript/jquery-plugin-autoresize/

$(document).ready(function () {
    $('.ExpandableTextCSS').autoResize({
        // On resize:
        onResize: function () {
            $(this).css({ opacity: 0.8 });
        },
        // After resize:
        animateCallback: function () {
            $(this).css({ opacity: 1 });
        },
        // Quite slow animation:
        animateDuration: 300,
        // More extra space:
        extraSpace:20,
        //Textarea height limit
        limit:10
    });
});


3

只是回顾一下,我已经做了一些整理(尽管对Prototype / JavaScript 满口的人可能会建议改进?)。

var TextAreaResize = Class.create();
TextAreaResize.prototype = {
  initialize: function(element, options) {
    element = $(element);
    this.element = element;

    this.options = Object.extend(
      {},
      options || {});

    Event.observe(this.element, 'keyup',
      this.onKeyUp.bindAsEventListener(this));
    this.onKeyUp();
  },

  onKeyUp: function() {
    // We need this variable because "this" changes in the scope of the
    // function below.
    var cols = this.element.cols;

    var linecount = 0;
    $A(this.element.value.split("\n")).each(function(l) {
      // We take long lines into account via the cols divide.
      linecount += 1 + Math.floor(l.length / cols);
    })

    this.element.rows = linecount;
  }
}

只需调用:

new TextAreaResize('textarea_id_name_here');

3

我做了一些很容易的事情。首先,我将TextArea放入DIV中。其次,我已经ready对该脚本调用了函数。

<div id="divTable">
  <textarea ID="txt" Rows="1" TextMode="MultiLine" />
</div>

$(document).ready(function () {
  var heightTextArea = $('#txt').height();
  var divTable = document.getElementById('divTable');
  $('#txt').attr('rows', parseInt(parseInt(divTable .style.height) / parseInt(altoFila)));
});

简单。它是div渲染后的最大高度,除以一行的一个TextArea的高度。


2

我自己需要此功能,但是我需要的这些功能都不起作用。

因此,我使用了Orion的代码并进行了更改。

我添加了一个最小高度,这样在破坏时它不会变得太小。

function resizeIt( id, maxHeight, minHeight ) {
    var text = id && id.style ? id : document.getElementById(id);
    var str = text.value;
    var cols = text.cols;
    var linecount = 0;
    var arStr = str.split( "\n" );
    $(arStr).each(function(s) {
        linecount = linecount + 1 + Math.floor(arStr[s].length / cols); // take into account long lines
    });
    linecount++;
    linecount = Math.max(minHeight, linecount);
    linecount = Math.min(maxHeight, linecount);
    text.rows = linecount;
};

2

就像@memical的答案一样。

但是我发现了一些改进。您可以使用jQuery height()函数。但是要注意顶部和底部的像素。否则,您的textarea将会增长得太快。

$(document).ready(function() {
  $textarea = $("#my-textarea");

  // There is some diff between scrollheight and height:
  //    padding-top and padding-bottom
  var diff = $textarea.prop("scrollHeight") - $textarea.height();
  $textarea.live("keyup", function() {
    var height = $textarea.prop("scrollHeight") - diff;
    $textarea.height(height);
  });
});

2

下面是我不使用jQuery的解决方案(因为有时它们不必是同一个东西)。尽管仅在Internet Explorer 7中对其进行了测试,所以社区可以指出所有错误的原因:

textarea.onkeyup = function () { this.style.height = this.scrollHeight + 'px'; }

到目前为止,我真的很喜欢它的工作方式,并且我不在乎其他浏览器,因此我可能会将其应用于我的所有文本区域:

// Make all textareas auto-resize vertically
var textareas = document.getElementsByTagName('textarea');

for (i = 0; i<textareas.length; i++)
{
    // Retain textarea's starting height as its minimum height
    textareas[i].minHeight = textareas[i].offsetHeight;

    textareas[i].onkeyup = function () {
        this.style.height = Math.max(this.scrollHeight, this.minHeight) + 'px';
    }
    textareas[i].onkeyup(); // Trigger once to set initial height
}

1

这是Jeremy在6月4日发布的Prototype小部件的扩展:

如果您在文本区域中使用限制,它将阻止用户输入更多字符。它检查是否还有字符。如果用户将文本复制到文本区域中,则文本将被最大程度地剪切掉。长度:

/**
 * Prototype Widget: Textarea
 * Automatically resizes a textarea and displays the number of remaining chars
 * 
 * From: http://stackoverflow.com/questions/7477/autosizing-textarea
 * 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'
    });

    // Keep the text/character count inside the limits:
    if($F(this.textarea).length > this.options.get('max_length')){
      text = $F(this.textarea).substring(0, this.options.get('max_length'));
        this.textarea.value = text;
        return false;
    }

    var remaining = this.options.get('max_length') - $F(this.textarea).length;
    this._remainingCharacters.update(Math.abs(remaining)  + ' characters remaining'));
  }
});

1

@memical有一个很棒的解决方案,可以使用jQuery在页面加载时设置文本区域的高度,但是对于我的应用程序,我希望能够随着用户添加更多内容而增加文本区域的高度。我通过以下方法构建了memical的解决方案:

$(document).ready(function() {
    var $textarea = $("p.body textarea");
    $textarea.css("height", ($textarea.attr("scrollHeight") + 20));
    $textarea.keyup(function(){
        var current_height = $textarea.css("height").replace("px", "")*1;
        if (current_height + 5 <= $textarea.attr("scrollHeight")) {
            $textarea.css("height", ($textarea.attr("scrollHeight") + 20));
        }
    });
});

它不是很平滑,但是它也不是面向客户端的应用程序,因此平滑性并不重要。(如果这是面向客户的,我可能会使用自动调整大小的jQuery插件。)


1

对于那些正在为IE编码并遇到此问题的人。IE有一个小技巧,使其成为100%CSS。

<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>

您甚至可以为IE提供的row =“ n”值提供一个值,但其他浏览器将使用该值。我真的很讨厌实现IE hacks的编码,但是这一步非常有帮助。可能仅在Quirks模式下有效。


1

Internet Explorer,Safari,Chrome和Opera用户需要记住在CSS中明确设置line-height值。我做一个样式表,为所有文本框设置初始属性,如下所示。

<style>
    TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>

1

这是我刚刚在jQuery中编写的一个函数,可以将其移植到Prototype,但它们不支持jQuery的“活动性”,因此Ajax请求添加的元素将不会响应。

此版本不仅可以扩展,而且在按Delete或Backspace时也可以收缩。

此版本依赖jQuery 1.4.2。

请享用 ;)

http://pastebin.com/SUKeBtnx

用法:

$("#sometextarea").textareacontrol();

或(例如,任何jQuery选择器)

$("textarea").textareacontrol();

已在Internet Explorer 7 / Internet Explorer 8,Firefox 3.5和Chrome上进行了测试。一切正常。


1

使用ASP.NET,只需执行以下操作:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Automatic Resize TextBox</title>
        <script type="text/javascript">
            function setHeight(txtarea) {
                txtarea.style.height = txtdesc.scrollHeight + "px";
            }
        </script>
    </head>

    <body>
        <form id="form1" runat="server">
            <asp:TextBox ID="txtarea" runat= "server" TextMode="MultiLine"  onkeyup="setHeight(this);" onkeydown="setHeight(this);" />
        </form>
    </body>
</html>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.