Как автоматически изменить размер текстовой области с помощью Prototype?

StackOverflow https://stackoverflow.com/questions/7477

Вопрос

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

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

Вот скриншот этого на данный момент.

ISO Address

Есть идеи?


@Крис

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

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

Решение

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

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

Никто из новичков в использовании Facebook, которых я знаю, никогда ничего об этом не упоминал и не был сбит с толку.Я бы использовал это как неофициальное свидетельство, чтобы сказать: «Давай, реализуй это».

Некоторый код 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>

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

Другие советы

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

Основной маршрут выглядит следующим образом:

  1. Создайте элемент контейнера для хранения textarea и скрытый div
  2. Используя Javascript, сохраните textareaсодержимое синхронизируется с divх
  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;
    width: 100%;
}
<div class="textarea-container">
    <textarea id="textArea"></textarea>
    <div id="textCopy"></div>
</div>

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

  • Использует высоту в пикселях вместо высоты строки:более точная обработка переноса строк при использовании пропорционального шрифта.
  • Принимает либо идентификатор, либо элемент в качестве входных данных
  • Принимает необязательный параметр максимальной высоты — полезно, если вы не хотите, чтобы текстовая область превышала определенный размер (сохраняйте все на экране, не нарушайте макет и т. д.).
  • Протестировано на Firefox 3 и Интернет Проводник 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, целится в текстовую область, в которую я сейчас печатаю - если у вас есть поджигатель установлено, вставьте оба образца в консоль и протестируйте на этой странице)

$("#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"; 
    });
});

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

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

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

Вот решение с 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');

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

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

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

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

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 height() функция.Но помните о пикселях с отступом сверху и снизу.В противном случае ваша текстовая область будет расти слишком быстро.

$(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);
  });
});

Мое решение, не использующее jQuery (потому что иногда они не обязательно должны быть одним и тем же), приведено ниже.Хотя это было проверено только в Интернет Проводник 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
}

Вот расширение виджета «Прототип», который Джереми опубликовал 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 у меня было отличное решение для установки высоты текстовой области при загрузке страницы с помощью 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 с автоматическим изменением размера.)

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

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

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

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();

Он был протестирован на Интернет Проводник 7/Интернет Проводник 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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top