WordPress как на ладони
wordpress jino

Автоматическое растягивание textarea на javascript и jQuery

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

Оглавление:

Вариант 1: авто-растягивания textarea (на чистом javascript)

Пожалуй это лучшее решение, поэтому это первый вариант.

Скрипт находится по этой ссылке: http://www.jacklmoore.com/autosize

А это прямая ссылка на сам javascript код, который нужно подключить к html: https://github.com/jackmoore/autosize/blob/master/src/autosize.js

Установка проста: подключаете файл скрипта с помощью wp_enqueue_script(). Затем подключаете растягивание к элементу textarea одним из следующих вариантов:

// список элементов
autosize( document.querySelectorAll('textarea') );

// один элемент
autosize( document.querySelector('textarea') );

// jQuery элементы
autosize( $('textarea') );

Поддержка браузеров:

Chrome Firefox IE Safari iOS Safari Android Opera Mini
yes yes 9 yes yes 4 ?

Вариант 2: авто-растягивания textarea (jQuery плагин)

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

Поделюсь сразу сжатой версией кода плагина:

/*
 * jQuery autoResize (textarea auto-resizer)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04.1 (kama fix)
 */
(function(b){b.fn.autoResize=function(f){var a=b.extend({onResize:function(){},animate:!0,animateDuration:150,animateCallback:function(){},extraSpace:20,limit:1E3},f);this.filter("textarea").each(function(){var d=b(this).css({"overflow-y":"hidden",display:"block"}),f=d.height(),g=function(){var c={};b.each(["height","width","lineHeight","textDecoration","letterSpacing"],function(b,a){c[a]=d.css(a)});return d.clone().removeAttr("id").removeAttr("name").css({position:"absolute",top:0,left:-9999}).css(c).attr("tabIndex","-1").insertBefore(d)}(),h=null,e=function(){g.height(0).val(b(this).val()).scrollTop(1E4);var c=Math.max(g.scrollTop(),f)+a.extraSpace,e=b(this).add(g);h!==c&&(h=c,c>=a.limit?b(this).css("overflow-y",""):(a.onResize.call(this),a.animate&&"block"===d.css("display")?e.stop().animate({height:c},a.animateDuration,a.animateCallback):e.height(c)))};d.unbind(".dynSiz").bind("keyup.dynSiz",e).bind("keydown.dynSiz",e).bind("change.dynSiz",e)});return this}})(jQuery);

// инициализация
jQuery(function(){
	jQuery('textarea').autoResize();
});

После установки этого кода, все textarea должны автоматически растягиваться.

Поддержка браузеров:

  • IE 6-8
  • Firefox 3.5
  • Opera 9.5-10
  • Safari 3
  • Chrome 10

Во время тестирования выяснил, что у textarea обязательно должно быть установлено css свойство display:block, иначе никакая анимация в плагине не работала (браузер chrome). Поэтому добавил в плагин пару строк кода, чтобы он сам устанавливал это свойство. Также, в некоторых браузерах есть возможность изменять размер поля вручную (в углу треугольничек), плагин эту возможность зачем-то убирал, я её вернул. Поэтому в заголовке @version 1.04.1 (kama fix)

Несжатая версия кода плагина:
/*
 * jQuery autoResize (textarea auto-resizer)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04.1 (kama fix)
 */
(function($){

	$.fn.autoResize = function(options) {

		// Just some abstracted details,
		// to make plugin users happy:
		var settings = $.extend({
			onResize : function(){

			},
			animate : true,
			animateDuration : 150,
			animateCallback : function(){},
			extraSpace : 20,
			limit: 1000
		}, options);

		// Only textarea's auto-resize:
		this.filter('textarea').each(function(){

				// Get rid of scrollbars and disable WebKit resizing:
			var textarea = $(this).css({'overflow-y':'hidden', display:'block'}),

				// Cache original height, for use later:
				origHeight = textarea.height(),

				// Need clone of textarea, hidden off screen:
				clone = (function(){

					// Properties which may effect space taken up by chracters:
					var props = ['height','width','lineHeight','textDecoration','letterSpacing'],
						propOb = {};

					// Create object of styles to apply:
					$.each(props, function(i, prop){
						propOb[prop] = textarea.css(prop);
					});

					// Clone the actual textarea removing unique properties
					// and insert before original textarea:
					return textarea.clone().removeAttr('id').removeAttr('name').css({
						position: 'absolute',
						top: 0,
						left: -9999
					}).css(propOb).attr('tabIndex','-1').insertBefore(textarea);

				})(),
				lastScrollTop = null,
				updateSize = function() {
					// Prepare the clone:
					clone.height(0).val($(this).val()).scrollTop(10000);

					// Find the height of text:
					var scrollTop = Math.max(clone.scrollTop(), origHeight) + settings.extraSpace,
						toChange = $(this).add(clone);

					// Don't do anything if scrollTip hasen't changed:
					if (lastScrollTop === scrollTop) { return; }
					lastScrollTop = scrollTop;

					// Check for limit:
					if ( scrollTop >= settings.limit ) {
						$(this).css('overflow-y','');
						return;
					}
					// Fire off callback:
					settings.onResize.call(this);

					// Either animate or directly apply height:
				   settings.animate && textarea.css('display') === 'block' ?
						toChange.stop().animate({height:scrollTop}, settings.animateDuration, settings.animateCallback)
						: toChange.height(scrollTop);

				};

			// Bind namespaced handlers to appropriate events:
			textarea
				.unbind('.dynSiz')
				.bind('keyup.dynSiz', updateSize)
				.bind('keydown.dynSiz', updateSize)
				.bind('change.dynSiz', updateSize);

		});

		// Chain:
		return this;

	};

})(jQuery);

Настройка плагина

Во время инициализации плагину можно установить некоторые параметры.

1. Уберем отступ снизу, по умолчанию он равен 20 пикселей:
jQuery('textarea').autoResize({
	 extraSpace : 0
});
2. Вешаем действия на события в момент ресайза и после него - настройки onResize и animateCallback:
jQuery('textarea').autoResize({
	// Во время ресайза:
	onResize : function() {
		jQuery(this).css({ color:'#666', background:'#eee' });
	},
	// После ресайза:
	animateCallback : function() {
		jQuery(this).css({ color:'#222', background:'#fff' });
	}
});

Все настройки

onResize(функция)
Функция вызывается в момент изменения размера textarea. Передает объект textarea, т.е. в функции "this" будет рабочий textarea.
animate(логический)
Включена ли анимация изменения высоты. true - включена.
По умолчанию: true
animateDuration(число)
Время, которое занимает анимация в миллисекундах.
По умолчанию: 150
animateCallback(функция)
Вызывается при окончании анимации.
extraSpace(число)
Отступ у textarea снизу в пикселях.
По умолчанию: 20
limit(число)
Максимальная высота textarea в пикселях. Выше появится скролл.
По умолчанию: 1000

Вариант 3: авто-растягивания textarea (мой старый скрипт)

Так сложилось, что первая версия скрипта для автоматического растягивания поля комментария в WordPress оказалась не самой лучшей smile. Когда я её тестировал почему то не заметил баг, который заключался в том, что при сильном растягивании поля, экран начинал прыгать наверх при нажатии на любую клавишу, в результате большой комментарий оставить вообще не представлялось возможным shock . Кроме этого, в IE 8 скрипт тормозил.

В общем, проведя не один час в попытках починить скрипт, я понял, что сделать это невозможно - нужно что-то кардинально менять. В результате, начал искать альтернативное решение. Попадались решения основанные на jQuery, но мне хотелось сделать на чистом JS. Решение с jQuery я оставил на крайний случай.

Серфинг вывел меня на решение, которое мне показалось приемлемым с точки зрения удобства. Посмотреть на это решение можете в этой демке (может кому пригодится). Немного поковырявшись со скриптом, я понял что сделать простую интеграцию в WordPress не получится (придется дополнять форму комментирования, добавлять CSS и конечно подключать сам Скрипт), а мне хотелось, чтобы было так: вставил скрипт и готово. Ведь, такое сомнительное юзабилити не стоит лишних усилий.

Поэтому я пошел сёрфить дальше и нашел интересную функцию подсчета строк, которую и доделал. Результат меня вполне устроил: взгляните на эту ДЕМО версию.

Из плюсов этого варианта изменения размеров поля комментирования, можно выделить:

  • простая интеграция в шаблон;
  • хороший подсчет высоты;
  • не тормозит.

Очередной новый вариант, от 16 декабря 2013 года. Подправил код, исправил баг - код был написан немного не корректно и мог нагружать компьютер. Теперь этого нет.

/** 
 * Скрипт для автоматического растягивания поля (Textarea) по вертикали. 
 *
 * Для работы скрипта высота textarea не должна быть определена жёстко, т.е.
 * НЕ должно быть определено CSS свойство height. Вместо height можно 
 * использовать min-height:200px; или лучше задать высоту через rows=''.
 * Также, можно ограничить максимальную высоту растяжки 
 * через CSS свойством max-height:800px;
 *
 * Автор: Тимур Камаев - http://wp-kama.ru
 * Версия 4.0
*/

// настройки
var krVar = {
	// id атрибут тега textarea
	textareaId: 'comment',
	// время пересчета (1000=1сек).
	repeat: 1000,
	// коэффициент. Увеличите, если появляется прокрутка.
	cof: 40, 

}

var KR = {
	timeout:0,
	textarea: document.getElementById( krVar.textareaId ),

	init: function(){
		if( ! KR.textarea )
			return;

		KR.textarea.onfocus = KR.doit;
		KR.textarea.onblur = KR.stop;
	},
	doit: function(){
		// устанавливаем нужное количество строк
		KR.textarea.rows = KR.countLines( KR.textarea.value );

		clearTimeout( KR.timeout );
		KR.timeout = setTimeout( function(){ KR.doit(); }, krVar.repeat );
	},
	stop: function(){
		clearTimeout( KR.timeout );
	},
	//функция подсчета строк
	countLines: function( strtocount ){
		var hard_lines = 0;
		var str = strtocount.split("\n");
		hard_lines = str.length;

		var tx = KR.textarea;
		var letter_width = tx.clientHeight / tx.rows * krVar.cof / 100; // приблизительная ширина одной буквы в пикселях
		var chars_in_line = tx.clientWidth / letter_width; //сколько букв в строке

		var lines = 0;
		var temp = 0;

		// hard_lines-1 = количество элементов в массиве
		for( i=0; i <= (hard_lines-1); i++ ){
			temp = str[i].length / chars_in_line;
			if( temp > 0 ) lines += temp;
		}   

		return lines + hard_lines;
	}
}

if( window.addEventListener )
	window.addEventListener( "load", KR.init, false );
else if( window.attachEvent )
	window.attachEvent( "onload", KR.init );

Установка скрипта

  1. Скопируйте вышеописанный код в любой уже имеющийся в шаблоне javascript файл;

  2. Установите полю textarea CSS свойство min-height (как это сделать см. ниже);

  3. (необязательно) Если не хотите, чтобы поле тянулось до бесконечности установите ему CSS свойство max-height;

Как вставить скрипт прямо в файл темы:

Если js файла у вас в шаблоне нет, то можно его создать, скопировать туда код, а затем подключить файл к шаблону.

Или можно просто подключить выше написанный код в ваш файл шаблона single.php, вставив такую конструкцию в файл:

<script type="text/javascript">/* <![CDATA[ */

Здесь код

/* ]]> */</script>

Как установить полю textarea css свойство min-height

Вариант 1: Откройте файл comments.php найдите там HTML тег textarea и добавьте к нему style='min-height:200px; max-height:700px;'. На вид примерно так:

<textarea style="min-height:200px; max-height:700px;" rows="58" name="comment" id="comment" tabindex="4"></textarea>

max-height:700px; можно не добавлять - это максимальная длинна до которой будет растягиваться поле.

Вариант 2: Найдите в вашем файле стилей (style.css) класс, который отвечает за поле textarea и добавьте к нему CSS свойство min-height:200px;. Если там присутствует свойство height:XXXpx, то его нужно удалить.

Несколько вариантов как может называться класс который отвечает за поле:

#commentform textarea

#respond textarea

#comment
textarea#comment

Тех. подробности: как работает скрипт

Принцип работы кода заключается в следующем: когда курсор попадает в поле комментирования включается периодический подсчет строк (каждые пол секунды), когда курсор выходит из поля, подсчет строк останавливается. Строки считаются путем суммы количества явных переносов строки (\n) и вычисление неявных переносов (когда строка переводится на новую из-за нехватки ширины поля, над этим моментом пришлось биться долго и муторно).

Принципиальная разница с прошлым вариантом в том, что применяется другая технология подсчета строк и строки считаются не по нажатию клавиши а спустя какое-то время, в нашем случае 500 миллисекунд (пол секунды). Интервал можно увеличить, если наблюдаются тормоза. В вариантах, когда подсчет высоты вешается на нажатие клавиши, везде наблюдаются тормоза, особенно на слабых компах и при быстром печатание.

Если возникнут вопросы задавайте в комментариях!

Автоматическое растягивание textarea на javascript и jQuery 24 комментария
Вопросы 1 Все
  • Twin cайт: sitestroyblog.ru

    Снова спасибо за скрипт. Проверил также на Chrome и IE - всё работает отлично.
    Но такое одно маленькое замечание. Параметр min-height указывается обязательно, иначе поле будет сжиматься до минимального после полной загрузки страницы и когда по ней нажимаешь. Для примера попробуйте у себя в стилях min-height вырезать и посмотрите что будет.
    P.S. По крайней мере, у себя заметил этот косяк. Параметр rows не спасает никак.

    Ответить7.3 лет назад #
    • Kama4697

      Вы правы, черт возьми smile А я подумал, что мне показалось. Обновил пост.

      Ответить7.3 лет назад #
  • eavasi cайт: www.eavasi.ru

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

    Ответить7 лет назад #
    • Kama4697

      Спасбо! Какие громкие слова, что кажутся они мне лестью. Нет, нет, я не буду брать все это на свой счет, это не совсем про меня пожалуй smile

      Ответить7 лет назад #
      • eavasi cайт: www.eavasi.ru

        Ну какой смысл, Тимур, мне льстить тебе? Я вовсе не хотел этого. Я передавал свои ощущения и абсолютно искренне.

        Ответить7 лет назад #
        • Kama4697

          Я ж написал, "что кажутся". В общем, на самом деле я не имел это ввиду.

          Ответить7 лет назад #
  • Shoostr cайт: lifeshop-ok.ru @

    Я в JS полный ноль, по этому сразу написать изменение в скрипте не смогу, но у меня возник вопрос: а нельзя ли как-нибудь пересчет делать не через каждые пол секунды а по событиям (onMouseOut, onMouseOver, onkeyup) т.е. повесить слушателя на эти события, мне кажется это меньше будет грузить браузер

    Ответить6.8 лет назад #
    • Kama4697

      Можно, изначально так и было на onkeyup повешено это грузит браузер чувствительно - жмешь любую кнопку и идет пересчет, если быстро пишешь тогда начинаются глюки...

      На onMouseOut, onMouseOver нелогично как-то совсем уж. Ну, навел мышку скрипт один раз пересчитал поле и все и пишешь коммент уже без растягивания...

      Ответить6.8 лет назад #
  • Shoostr @

    в любом случае спс , применил скрипт в работе,

    порыскав в инете нашел еще один скриптик:

    <textarea style="width:600px; font-size:14px; height:100px;"
    onkeyup="this.style.height=(a=(e=parseInt(this.style.fontSize)*(this.value.split('\n').length+2))
    >(e2=700)?e2:e)<100?100:a;"></textarea>

    который мне понравился тем что он ну уж очень маленький небольшой скролл не мешает, работает от события onkeyup, был баг на копирование туда текста при помощи клика мыши, легко его устранил добавив событие onMouseOut. Проблема в том что он не работает в IE и в GoogleChrome. Может кто знает как решить эту проблемку?

    Ответить6.8 лет назад #
    • Kama4697

      Интересный пример, я его вроде тоже пробовал, когда этот скрипт делал.

      Точно не помню сейчас, но вроде style.height в разных браузерах понимается по-разному, поэтому опираясь на это число невозможно сделать такой скрипт кроссбраузерным.

      У меня в последнем IE и в GoogleChrome 8+, все работает.

      Ответить6.8 лет назад #
  • virtual cайт: see.od.ua @

    Во всех вышеуказанных скриптах когда вставляешь большой текст из буфера textarea не растягивается. sad

    Ответить6.7 лет назад #
    • Kama4697

      Дополнил статью вариантом на jQuery, который подключил к этому блогу. Все работает на ура!

      Ответить6.7 лет назад #
      • virtual cайт: see.od.ua @

        Точно.

        Ответить6.7 лет назад #
        • Kama4697

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

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

          П.С. Обновил пост, думаю теперь он точно заслуживает внимания smile

          Ответить6.7 лет назад #
          • virtual cайт: see.od.ua @

            А говоришь javascript плохо знаешь. wink

            Ответить6.7 лет назад #
            • Kama4697

              Так я его плохо знаю. Пока сделал замучился. Там даже не столько javascript сколько идея как реализовать, впрочем, так везде: язык - лишь средство. crazy

              Ответить6.7 лет назад #
  • Юрий

    Развитие скрипта

    • jQuery autoResize (textarea auto-resizer)
    • @copyright James Padolsey http://james.padolsey.com
    • @version 1.04
      https://github.com/padolsey/jQuery.fn.autoResize
      В отличии от упомянутой версии 1.04 как минимум умеет распахивать высоту с учетом ЗАРАНЕЕ введенного содержимого textarea.
      То есть
      <textarea>тут, например из БД, выводится много текста для редактирования и этот текст будет учтен в высоте</textarea>

      .

    Ответить5.9 лет назад #
  • Leonid @

    Не работает((

    Ответить5.6 лет назад #
  • Наталья

    Спасибо большое! js вариант работает отлично. Единственное, если указывать высоту, например, через rows="5", как рекомендуется в аннотации, то при постановке курсора в поле, поле сокращалось до 1 строки (Chrome). С указанием минимальной высоты в px такого не стало. Но это мелочь. Зато удобно очень, когда подобный эффект нужен для отдельных textarea на отдельно взятой странице good

    Ответить3.3 года назад #
  • Виктор @

    Спасибо, все понятно на вашем сайте. Это редкость, когда так все точно и понятно описано. Сообразил даже такой чайник, как я dash

    Буду внедрять ваш нелегкий труд, и очень надеюсь на положительный результат. boast

    Ответить1.7 года назад #
  • А как подключить скрипт (из первого варианта) к одному элементу? Я имею ввиду вот это:

    autosize( document.querySelector('textarea') );

Здравствуйте, !

Ваш комментарий