Создание текстовой области с автоматическим изменением размера - PullRequest
309 голосов
/ 18 января 2009

Был другой поток об этом , который я пробовал. Но есть одна проблема: textarea не уменьшается при удалении контента. Я не могу найти способ уменьшить его до правильного размера - значение clientHeight возвращается как полный размер textarea, а не его содержимое.

Код с этой страницы ниже:

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

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

window.onload = function() {
    document.getElementById("ta").onkeyup = function() {
      FitToContent( this, 500 )
    };
}

Ответы [ 38 ]

279 голосов
/ 02 сентября 2014

ПОЛНОЕ ПОЛНОЕ РЕШЕНИЕ

Обновлено 07/05/2019 (улучшена поддержка браузеров для мобильных телефонов и планшетов)

Будет работать следующий код:

  • При вводе с клавиатуры.
  • со вставленным текстом (щелкните правой кнопкой мыши и Ctrl + V).
  • С вырезанным текстом (щелкните правой кнопкой мыши и Ctrl + X).
  • С предварительно загруженным текстом.
  • Со всеми текстовыми областями (многострочными текстовыми полями) по всему сайту.
  • С Firefox (протестировано v31-67).
  • С Хром (протестировано v37-74).
  • С IE (протестировано v9-v11).
  • С Край (протестировано v14-v18).
  • С IOS Safari .
  • С Браузером Android .
  • С JavaScript строгий режим .
  • Проверено w3c .
  • И оптимизирован и эффективен.

ВАРИАНТ 1 (с jQuery)

Для этого параметра требуется jQuery , он был протестирован и работает с 1.7.2 - 3.3.1

Простой (Добавьте этот код jquery в свой файл основного сценария и забудьте об этом.)

$('textarea').each(function () {
  this.setAttribute('style', 'height:' + (this.scrollHeight) + 'px;overflow-y:hidden;');
}).on('input', function () {
  this.style.height = 'auto';
  this.style.height = (this.scrollHeight) + 'px';
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea placeholder="Type, paste, cut text here...">PRELOADED TEXT.
This javascript should now add better support for IOS browsers and Android browsers.</textarea>
<textarea placeholder="Type, paste, cut text here..."></textarea>

Тест на jsfiddle


ВАРИАНТ 2 (Чистый JavaScript)

Простой (Добавьте этот JavaScript в свой основной файл сценария и забудьте об этом.)

var tx = document.getElementsByTagName('textarea');
for (var i = 0; i < tx.length; i++) {
  tx[i].setAttribute('style', 'height:' + (tx[i].scrollHeight) + 'px;overflow-y:hidden;');
  tx[i].addEventListener("input", OnInput, false);
}

function OnInput() {
  this.style.height = 'auto';
  this.style.height = (this.scrollHeight) + 'px';
}
<textarea placeholder="Type, paste, cut text here...">PRELOADED TEXT. This JavaScript should now add better support for IOS browsers and Android browsers.</textarea>
<textarea placeholder="Type, paste, cut text here..."></textarea>

Тест на jsfiddle


ВАРИАНТ 3 (расширение jQuery)

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

jQuery.fn.extend({
  autoHeight: function () {
    function autoHeight_(element) {
      return jQuery(element)
        .css({ 'height': 'auto', 'overflow-y': 'hidden' })
        .height(element.scrollHeight);
    }
    return this.each(function() {
      autoHeight_(this).on('input', function() {
        autoHeight_(this);
      });
    });
  }
});

Вызвать с $('textarea').autoHeight()


ОБНОВЛЕНИЕ ТЕКСТАРЕА ВИА JAVASCRIPT

При добавлении содержимого в текстовую область через JavaScript добавьте следующий код, чтобы вызвать функцию в опции 1.

$('textarea').trigger('input');
196 голосов
/ 18 марта 2011

Это работает для меня (Firefox 3.6 / 4.0 и Chrome 10/11):

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();
}
textarea {
    border: 0 none white;
    overflow: hidden;
    padding: 0;
    outline: none;
    background-color: #D0D0D0;
}
<body onload="init();">
<textarea rows="1" style="height:1em;" id="text"></textarea>
</body>

Если хотите, попробуйте на jsfiddle Он начинается с одной строки и вырастает только необходимое количество. Это нормально для одного textarea, но я хотел написать что-то, где у меня было бы много-много таких textarea (примерно столько же, сколько обычно у строк в большом текстовом документе). В этом случае это действительно медленно. (В Firefox это безумно медленно.) Поэтому я действительно хотел бы подход, который использует чистый CSS. Это было бы возможно с contenteditable, но я хочу, чтобы это было только для открытого текста.

62 голосов
/ 15 декабря 2011

Решение jQuery отрегулируйте CSS в соответствии с вашими требованиями

CSS ...

div#container textarea {
    min-width: 270px;
    width: 270px;
    height: 22px;
    line-height: 24px;
    min-height: 22px;
    overflow-y: hidden; /* fixes scrollbar flash - kudos to @brettjonesdev */
    padding-top: 1.1em; /* fixes text jump on Enter keypress */
}

Javascript ...

// auto adjust the height of
$('#container').delegate( 'textarea', 'keydown', function (){
    $(this).height( 0 );
    $(this).height( this.scrollHeight );
});
$('#container').find( 'textarea' ).keydown();

ИЛИ альтернатива для jQuery 1.7 + ...

// auto adjust the height of
$('#container').on( 'keyup', 'textarea', function (){
    $(this).height( 0 );
    $(this).height( this.scrollHeight );
});
$('#container').find( 'textarea' ).keyup();

Я создал скрипку с абсолютным минимальным стилем в качестве отправной точки для ваших экспериментов ... http://jsfiddle.net/53eAy/951/

28 голосов
/ 24 июля 2012
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Textarea autoresize</title>
    <style>
    textarea {
        overflow: hidden;
    }
    </style>
    <script>
    function resizeTextarea(ev) {
        this.style.height = '24px';
        this.style.height = this.scrollHeight + 12 + 'px';
    }

    var te = document.querySelector('textarea');
    te.addEventListener('input', resizeTextarea);
    </script>
</head>
<body>
    <textarea></textarea>
</body>
</html>

Проверено в Firefox 14 и Chromium 18. Числа 24 и 12 являются произвольными, проверьте, что подходит вам лучше всего.

Вы могли бы обойтись без тегов style и script, но имхо становится немного грязно (это старый стиль HTML + JS и не рекомендуется).

<textarea style="overflow: hidden" onkeyup="this.style.height='24px'; this.style.height = this.scrollHeight + 12 + 'px';"></textarea>

Редактировать: модернизированный код. Изменен атрибут onkeyup на addEventListener.
Изменить: keydown работает лучше, чем keyup
Редактировать: объявить функцию перед использованием
Редактировать: ввод работает лучше, чем нажатие клавиши (thnx @ WASD42 & @ MA-Maddin)

jsfiddle

24 голосов
/ 29 декабря 2015

Лучшее решение (работает и коротко) для меня:

    $(document).on('input', 'textarea', function () {
        $(this).outerHeight(38).outerHeight(this.scrollHeight); // 38 or '1em' -min-height
    }); 

Работает как брелок, не мигая пастой (также с мышью), вырезая, вводя и сжимаясь до нужного размера

Пожалуйста, посмотрите на jsFiddle .

16 голосов
/ 18 января 2009

Вы используете более высокое значение текущего clientHeight и содержимого scrollHeight. Когда вы уменьшаете scrollHeight, удаляя содержимое, вычисляемая область не может уменьшаться, потому что clientHeight, ранее установленный style.height, держит его открытым. Вместо этого вы можете взять max () из scrollHeight и минимальное значение высоты, которое вы предварительно определили или рассчитали из textarea.rows.

В общем, вам, вероятно, не стоит полагаться на scrollHeight в элементах управления формы. Помимо того, что scrollHeight традиционно менее широко поддерживается, чем некоторые другие расширения IE, HTML / CSS ничего не говорит о внутренней реализации элементов управления формы, и вы не гарантируете, что scrollHeight будет что-то значимым. (Традиционно некоторые браузеры использовали для этой задачи виджеты ОС, что делает невозможным взаимодействие CSS и DOM на их внутренних объектах.) По крайней мере, проанализируйте наличие scrollHeight / clientHeight, прежде чем пытаться включить эффект.

Другой возможный альтернативный подход, позволяющий избежать проблемы, если важно, чтобы он работал более широко, может заключаться в использовании скрытого элемента div, имеющего ширину, равную ширине текстовой области, и установленного в том же шрифте. При keyup вы копируете текст из текстовой области в текстовый узел в скрытом div (не забывая заменить '\ n' на разрыв строки и экранировать '<' / '&' правильно, если вы используете innerHTML). Затем просто измерив смещение divHeight, вы получите необходимую высоту. </p>

14 голосов
/ 25 июля 2014

Если вам не нужна поддержка IE8, вы можете использовать событие input:

var resizingTextareas = [].slice.call(document.querySelectorAll('textarea[autoresize]'));

resizingTextareas.forEach(function(textarea) {
  textarea.addEventListener('input', autoresize, false);
});

function autoresize() {
  this.style.height = 'auto';
  this.style.height = this.scrollHeight+'px';
  this.scrollTop = this.scrollHeight;
  window.scrollTo(window.scrollLeft,(this.scrollTop+this.scrollHeight));
}

Теперь вам нужно только добавить немного CSS, и все готово:

textarea[autoresize] {
  display: block;
  overflow: hidden;
  resize: none;
}

Использование:

<textarea autoresize>Type here and I’ll resize.</textarea>

Вы можете узнать больше о том, как это работает в моем блоге .

11 голосов

авторазмер

https://github.com/jackmoore/autosize

Просто работает, автономно, популярно (3.0k + звезды GitHub по состоянию на октябрь 2018), доступно на cdnjs ) и легкое (~ 3.5k). Демонстрация:

<textarea id="autosize" style="width:200px;">a
J   b
c</textarea>
<script src="https://cdnjs.cloudflare.com/ajax/libs/autosize.js/4.0.2/autosize.min.js"></script>
<script>autosize(document.querySelectorAll('#autosize'));</script>

Кстати, если вы используете редактор ACE, используйте maxLines: Infinity: Автоматическая настройка высоты содержимого в редакторе Ace Cloud 9

6 голосов
/ 17 октября 2014

Кто-нибудь посчитал спорным? Нет необходимости возиться с прокруткой, и единственное, что мне нравится в JS, это то, что вы планируете сохранять данные в режиме размытия ... и, очевидно, оно совместимо во всех популярных браузерах:

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

Что здорово в этом подходе, так это то, что вы можете сохранять теги в некоторых браузерах.

http://jsfiddle.net/gbutiri/v31o8xfo/

<style>
.autoheight {
    min-height: 16px;
    font-size: 16px;
    margin: 0;
    padding: 10px;
    font-family: Arial;
    line-height: 16px;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    overflow: hidden;
    resize: none;
    border: 1px solid #ccc;
    outline: none;
    width: 200px;
}
</style>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script>
$(document).on('blur','.autoheight',function(e) {
    var $this = $(this);
    // The text is here. Do whatever you want with it.
    console.log($this.html());
});

</script>
<div class="autoheight contenteditable" contenteditable="true">Mickey Mouse</div>
4 голосов
/ 17 июля 2014

Есть немного другой подход.

<code><div style="position: relative">
  <pre style="white-space: pre-wrap; word-wrap: break-word">

Идея состоит в том, чтобы скопировать текст из textarea в pre и позволить CSS убедиться, что они имеют одинаковый размер.

Преимущество заключается в том, что фреймворки предоставляют простые инструменты для перемещения текста без каких-либо событий. А именно, в AngularJS вы бы добавили ng-model="foo" ng-trim="false" к textarea и ng-bind="foo + '\n'" к pre. См скрипка .

Просто убедитесь, что pre имеет тот же размер шрифта, что и textarea.

...