Автоматическое растягивание текстовой области в JavaScript

# Автоматическое изменение размера текстовой области в JavaScript и jQuery

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

## Содержание

- Опция 1: Автоматическое изменение размера текстовой об��асти с помощью чистого JavaScript
- Опция 2: Автоматическое изменение размера текстовой области с помощью плагина jQuery
- Вариант 3: Авторастягивающаяся текстовая область (мой старый скрипт)

## Опция 1: Автоматическое изменение размера текстовой области с помощью чистого JavaScript

Это, пожалуй, самое простое решение, и мы начнем именно с него.

Скрипт можно найти [здесь](https://github.com/jackmoore/autosize). Вам нужно добавить JavaScript код в ваш HTML. 

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

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

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

// для jQuery элементов
autosize($('textarea'));

Поддержка браузерами

Браузер Chrome Firefox IE Safari iOS Safari (Android) Opera Mini
Поддержка да да 9 да да 4 ?

Опция 2: Автоматическое изменение размера текстовой области с помощью плагина jQuery

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

Вот минимизированная версия кода плагина:

/*
 * jQuery autoResize (автоизменение размера текстовой области)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04.1 (исправление от Kama)
 */
(function($) {
    $.fn.autoResize = function(options) {
        var settings = $.extend({
            onResize: function() {},
            animate: true,
            animateDuration: 150,
            animateCallback: function() {},
            extraSpace: 20,
            limit: 1000
        }, options);

        this.filter('textarea').each(function() {
            var textarea = $(this).css({'overflow-y': 'hidden', display: 'block'}),
                origHeight = textarea.height(),
                clone = (function() {
                    var props = ['height', 'width', 'lineHeight', 'textDecoration', 'letterSpacing'],
                        propOb = {};

                    $.each(props, function(i, prop) {
                        propOb[prop] = textarea.css(prop);
                    });

                    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() {
                    clone.height(0).val($(this).val()).scrollTop(10000);
                    var scrollTop = Math.max(clone.scrollTop(), origHeight) + settings.extraSpace,
                        toChange = $(this).add(clone);

                    if (lastScrollTop === scrollTop) { return; }
                    lastScrollTop = scrollTop;

                    if (scrollTop >= settings.limit) {
                        $(this).css('overflow-y', '');
                        return;
                    }
                    settings.onResize.call(this);
                    settings.animate && textarea.css('display') === 'block' ?
                        toChange.stop().animate({height: scrollTop}, settings.animateDuration, settings.animateCallback) :
                        toChange.height(scrollTop);
                };

            textarea.unbind('.dynSiz').bind('keyup.dynSiz', updateSize)
                .bind('keydown.dynSiz', updateSize)
                .bind('change.dynSiz', updateSize);
        });

        return this;
    };

})(jQuery);

Поддержка браузерами

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

Во время тестирования было обнаружено, что для корректной работы плагина текстовая область должна иметь CSS свойство display: block, иначе анимация не работала (в браузере Chrome). Также некоторые браузеры позволяли вручную изменять размер текстовой области, но плагин этого не поддерживал.

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

При инициализации плагина можно установить определенные параметры:

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

Опция 3: Авторастягивающаяся текстовая область (мой старый скрипт)

Первая версия моего скрипта для автоматического растягивания текстовой области в WordPress оказалась не лучшей. При тестировании я не заметил баг, из-за которого экран поднимался при значительном растягивании поля, что усложняло оставление больших комментариев. Кроме того, скрипт лагал в IE 8.

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

В итоге я нашел функцию для подсчета строк и улучшил ее. Вот более подробное описание работы нового варианта.

Преимущества этого варианта

  • Простота интеграции в шаблон.
  • Хорошая оценка высоты.
  • Нет лагов.

Код нового скрипта

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

// настройки
var krVar = {
    // ID атрибута тега текстовой области
    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 (var i = 0; i <= (hard_lines - 1); i++) {
            temp = str[i].length / chars_in_line;
            if (temp > 0) lines += temp;
        }

        return lines + hard_lines;
    }
}

window.addEventListener("load", KR.init, false);

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

  1. Скопируйте код выше в любой существующий JavaScript файл вашего шаблона.
  2. Установите CSS свойство min-height для текстовой области (см. ниже).
  3. (опционально) Если вы не хотите, чтобы поле растягивалось бесконечно, установите CSS свойство max-height.

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

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

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

Как установить свойство CSS min-height для текстовой области

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

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

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

Возможные имена классов для поля:

#commentform textarea{}
#respond textarea{}
#comment{}
textarea#comment{}

Технические детали: Как работает скрипт

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

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

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

Leave a Reply

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