How to autosize a textarea using Prototype?
В настоящее время я работаю над приложением по внутренним продажам для компании, в которой я работаю, и у меня есть форма, которая позволяет пользователю изменить адрес доставки.
Теперь я думаю, что это выглядело бы намного лучше, если бы текстовое поле, которое я использую для основных деталей адреса, просто заняло бы область текста в нем и автоматически изменило бы размер, если текст был изменен.
Вот скриншот этого в настоящее время.
Есть идеи?
@Крис
Хороший вопрос, но есть причины, по которым я хочу изменить его размер. Я хочу, чтобы область, которую он занимает, была областью информации, содержащейся в нем. Как вы можете видеть на скриншоте, если у меня фиксированная текстовая область, она занимает довольно много места в вертикальном пространстве.
Я могу уменьшить шрифт, но мне нужно, чтобы адрес был крупным и читабельным. Теперь я могу уменьшить размер текстовой области, но у меня возникают проблемы с людьми, у которых адресная строка занимает 3 или 4 (одна занимает 5) строк. Потребность в том, чтобы пользователь использовал полосу прокрутки, является основной нет-нет.
Я думаю, я должен быть более конкретным. Я после вертикального изменения размера, и ширина не имеет большого значения. Единственная проблема, которая возникает при этом, заключается в том, что число ISO (большое "1") помещается под адресом, когда ширина окна слишком мала (как вы можете видеть на скриншоте).
Дело не в том, чтобы иметь уловку; Речь идет о текстовом поле, которое пользователь может редактировать, которое не будет занимать ненужного места, но покажет весь текст в нем.
Хотя, если кто-то придумает другой способ решения проблемы, я тоже открыт для этого.
Я немного изменил код, потому что он немного странный. Я изменил его, чтобы активировать при keyup, потому что он не будет учитывать только что набранный символ.
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;
};
18 ответов
Facebook делает это, когда вы пишете на стенах людей, но изменяете размеры только по вертикали.
Горизонтальное изменение размера кажется мне беспорядком из-за переноса слов, длинных строк и т. Д., Но вертикальное изменение размера кажется довольно безопасным и приятным.
Никто из тех новичков, использующих Facebook, которые я знаю, никогда не упоминал об этом и не был сбит с толку. Я бы использовал это в качестве неподтвержденного доказательства, чтобы сказать "давай, реализуй".
Некоторый код JavaScript для этого, используя Prototype (потому что это то, с чем я знаком):
<!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>
PS: Очевидно, что этот код JavaScript очень наивен и не очень хорошо протестирован, и вы, вероятно, не хотите использовать его в текстовых полях с новеллами в них, но вы поймете общую идею.
Одним из уточнений некоторых из этих ответов является предоставление CSS большей работы.
Основной маршрут выглядит следующим образом:
- Создайте элемент контейнера для хранения
textarea
и скрытыйdiv
- Используя Javascript, сохраните
textarea
содержимое синхронизировано сdiv
"s - Пусть браузер выполняет работу по вычислению высоты этого div
- Потому что браузер обрабатывает рендеринг / определение размеров скрытых
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>
Вот еще один метод автоматического определения размера текстовой области.
- Использует высоту пикселя вместо высоты строки: более точная обработка переноса строки, если используется пропорциональный шрифт.
- Принимает ID или элемент в качестве ввода
- Принимает необязательный параметр максимальной высоты - полезно, если вы не хотите, чтобы текстовая область увеличивалась до определенного размера (сохраняйте все это на экране, избегайте нарушения макета и т. Д.)
- Протестировано на Firefox 3 и Internet Explorer 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, цели на текстовой области, в которую я сейчас набираю - если у вас установлен Firebug, вставьте оба примера в консоль и протестируйте на этой странице)
$("#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";
});
});
Таким образом, вам не нужны никакие скрытые элементы или что-то подобное.
Примечание: возможно, вам придется поиграть с 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
});
});
Просто вернувшись к этому, я сделал его немного более аккуратным (хотя кто-то, кто полон бутылок на Prototype/ 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 одной строки.
Мое решение не использовать JQuery (потому что иногда они не должны быть одинаковыми) ниже. Хотя это было протестировано только в Internet Explorer 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
}
Я нуждался в этой функции для себя, но ни один из них не работал так, как я нуждался в них.
Поэтому я использовал код Ориона и изменил его.
Я добавил минимальную высоту, чтобы при разрушении она не становилась слишком маленькой.
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()
функция. Но следует помнить о пикселях padding-top и padding-bottom. В противном случае ваша текстовая область будет расти слишком быстро.
$(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);
});
});
Для тех, кто кодирует IE и сталкивается с этой проблемой. IE имеет небольшой трюк, который делает его 100% CSS.
<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>
Вы можете даже указать значение для row ="n", которое IE будет игнорировать, но другие браузеры будут его использовать. Я действительно ненавижу кодирование, которое реализует взломы IE, но этот очень полезен. Возможно, он работает только в режиме Quirks.
Пользователям Internet Explorer, Safari, Chrome и Opera необходимо помнить, чтобы точно установить значение высоты строки в CSS. Я делаю таблицу стилей, которая устанавливает начальные свойства для всех текстовых полей следующим образом.
<style>
TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>
У @memical было отличное решение для установки высоты текстовой области при загрузке страниц с помощью jQuery, но для моего приложения я хотел иметь возможность увеличивать высоту текстовой области, когда пользователь добавляет больше контента. Я построил решение мемула со следующим:
$(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 с автоматическим изменением размера.)
Вот функция, которую я только что написал в jQuery для этого - вы можете перенести ее на Prototype, но они не поддерживают "живость" jQuery, поэтому элементы, добавленные запросами Ajax, не будут отвечать.
Эта версия не только расширяется, но и сокращается при нажатии клавиши удаления или возврата.
Эта версия опирается на jQuery 1.4.2.
Наслаждаться;)
Использование:
$("#sometextarea").textareacontrol();
или (любой селектор jQuery, например)
$("textarea").textareacontrol();
Он был протестирован в Internet Explorer 7/ Internet Explorer 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>
Вот расширение виджета Prototype, который Джереми разместил 4 июня:
Он запрещает пользователю вводить больше символов, если вы используете ограничения в текстовых областях. Он проверяет, остались ли символы. Если пользователь копирует текст в текстовую область, текст обрезается на макс. длина:
/**
* Prototype Widget: Textarea
* Automatically resizes a textarea and displays the number of remaining chars
*
* From: http://stackru.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'));
}
});