WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

Автоматическое растягивание 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 миллисекунд (пол секунды). Интервал можно увеличить, если наблюдаются тормоза. В вариантах, когда подсчет высоты вешается на нажатие клавиши, везде наблюдаются тормоза, особенно на слабых компах и при быстром печатание.

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

23 коммента
    Войти