Автоматическое изменение размеров textarea с помощью прототипа


в настоящее время я работаю над внутренним приложением продаж для компании, в которой я работаю, и у меня есть форма, которая позволяет пользователю изменять адрес доставки.

теперь я думаю, что это будет выглядеть намного лучше, если textarea, который я использую для основных деталей адреса, просто займет область текста в нем и автоматически изменит размер, если текст был изменен.

вот скриншот этого в настоящее время.

любой идеи?


@Chris

хороший момент, но есть причины, по которым я хочу его изменить. Я хочу, чтобы область, которую он занимает, была областью информации, содержащейся в нем. Как вы можете видеть на снимке экрана, если у меня есть фиксированная текстовая область, она занимает довольно много вертикального пространства.

Я могу уменьшить шрифт, но мне нужен адрес, чтобы быть крупным и читаемым. Теперь я могу уменьшить размер текстовой области, но тогда у меня есть проблемы с людьми, у которых есть адресная строка, которая занимает 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;
};
18 110

18 ответов:

Facebook делает это, когда вы пишете на стенах людей, но только изменяет размер по вертикали.

горизонтальный размер поражает меня как беспорядок, из-за переноса слов, длинных строк и т. д., Но вертикальный размер кажется довольно безопасным и приятным.

ни один из Facebook-using-новичков, которых я знаю, никогда не упоминал об этом или не был смущен. Я бы использовал это как анекдотическое свидетельство, чтобы сказать: "Продолжайте, реализуйте его".

код 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>

одно уточнение к некоторым из этих ответов состоит в том, чтобы позволить CSS делать больше работы.

основной маршрут, кажется:

  1. создать элемент контейнера для хранения textarea и скрытый div
  2. используя Javascript, сохраните textareaсодержимое синхронизировано с div ' s
  3. пусть браузер сделает работу по вычислению высоты этого div
  4. потому что браузер обрабатывает рендеринг / размер скрытого div, мы избегать явно устанавливая textarea ' s высота.

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;
    width: 100%;
}
<div class="textarea-container">
    <textarea id="textArea"></textarea>
    <div id="textCopy"></div>
</div>

вот еще один метод для автоматического изменения размера текстового поля.

  • использует высоту пикселя вместо высоты линии: более точная обработка переноса линии, если используется пропорциональный шрифт.
  • принимает либо 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";
   }
}

Demo: (использует jQuery, цели в текстовом поле, в которое я набираю прямо сейчас - если у вас есть Firebug установлено, вставьте оба образца в консоль и протестируйте на этой странице)

$("#post-text").keyup(function()
{
   FitToContent(this, document.documentElement.clientHeight)
});

наверное, самое короткое решение:

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

таким образом, вам не нужно никаких скрытых дивов или что-нибудь в этом роде.

Примечание: возможно, вам придется играть с this.style.height = (this.scrollHeight) + "px"; в зависимости от того, как вы стилизуете текстовую область (высота строки, заполнение и т. д.).

здесь прототип версия изменение размера текстовой области, которая не зависит от количества столбцов в textarea. Это превосходный метод, потому что он позволяет управлять текстовой областью с помощью 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);
  });   
});

вот решение с JQuery:

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

abc это teaxtarea.

Проверьте ссылку ниже: 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
    });
});

просто возвращаясь к этому, я сделал его немного аккуратнее (хотя кто-то, кто полон бутылки на прототип/код 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');

Я сделал кое-что довольно легко. Сначала я поместил текстовое поле в 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 после его визуализации, разделенная на высоту одного текстового поля одной строки.

Мне нужна была эта функция для себя, но ни одна из них не работала так, как мне нужно.

поэтому я использовал код Ориона и изменил его.

Я добавил в минимальную высоту, так что на разрушение он не становится слишком маленьким.

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

как ответ @memical.

однако я нашел некоторые улучшения. Вы можете использовать jQuery

вот расширение к прототипу виджета, который Джереми опубликовал 4 июня:

это останавливает пользователя от ввода большего количества символов, если вы используете ограничения в текстовых областях. Он проверяет, остались ли символы. Если пользователь копирует текст в текстовую область, текст обрезается по максимуму. длина:

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

@memical было удивительное решение для установки высоты textarea на pageload с jQuery, но для моего приложения я хотел иметь возможность увеличить высоту textarea, как пользователь добавил больше контента. Я построил решение 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.)

для тех, которые кодируют для IE и сталкиваются с этой проблемой. IE имеет небольшой трюк, который делает его 100% CSS.

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

вы даже можете указать значение для строк= "n", которое IE будет игнорировать, но другие браузеры будут использовать. Я действительно ненавижу кодирование, которое реализует IE хаки, но это очень полезно. Вполне возможно, что он работает только в режиме совместимости.

Internet Explorer, Safari, Chrome и Опера пользователи должны помнить, чтобы явно установить значение высоты линии в CSS. Я делаю таблицу стилей, которая задает начальные свойства для всех текстовых полей следующим образом.

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

вот функция, которую я только что написал в jQuery, чтобы сделать это - вы можете перенести его в прототип, но они не поддерживают "живость" 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. Все работает нормально.

использование 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>

мое решение не использовать 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
}