如何使用 Prototype 自动调整文本区域?

我目前正在为我工作的公司编写一个内部销售应用程序,我有一个允许用户更改送货地址的表单。

现在我认为它看起来会更好,如果我使用的文本区域的主要地址细节将只占用其中的文本区域,并自动调整大小,如果文本被改变。

下面是目前的截图。

ISO Address

有什么想法吗?


@ Chris

有道理,但我想调整尺寸是有原因的。我希望它占据的区域是包含在其中的信息的区域。正如你在屏幕截图中看到的,如果我有一个固定的文本区域,它会占用相当多的垂直空间。

我可以减少字体,但我需要的地址是大和可读的。现在我可以减少文本区域的大小,但是我有问题的人谁有一个地址线需要3或4(一个需要5)行。需要让用户使用滚动条是一个主要的禁忌。

我想我应该说得更具体一点。我在调整垂直尺寸,宽度并不那么重要。唯一的问题是,当窗口宽度太小时,ISO 编号(大的“1”)会被推到地址下面(正如你在截图中看到的那样)。

这不是一个噱头,而是一个用户可以编辑的文本字段,它不会占用不必要的空间,但会显示其中的所有文本。

不过,如果有人想出另一种方法来解决这个问题,我也愿意接受。


我稍微修改了一下代码,因为它的行为有点奇怪。我改变了它,以激活键盘上,因为它不会考虑的字符,刚刚输入。

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;
};
158275 次浏览

当你在人们的墙上写字时,Facebook 就是这样做的,但只是垂直调整大小。

横向调整大小给我的印象是一团糟,因为文字包装,长行,等等,但垂直调整大小似乎是相当安全和美好的。

我认识的那些使用 Facebook 的新手中,没有一个人提到过这件事,也没有一个人对此感到困惑。我会用这句话作为轶事证据来说“去吧,实施它”。

一些 JavaScript 代码,使用 原型机(因为这是我所熟悉的) :

<!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 代码非常幼稚,没有经过很好的测试,你可能不想在文本框中使用它,但是你可以大致了解一下。

下面是另一种自动调整文本区域大小的技术。

  • 使用像素高度代替行高: 如果使用比例字体,更精确地处理行包装。
  • 接受 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,我现在正在输入的文本区域的目标——如果你已经安装了 纵火犯,将两个样本粘贴到控制台并在这个页面上进行测试)

$("#post-text").keyup(function()
{
FitToContent(this, document.documentElement.clientHeight)
});

只是重温一下,我已经使它变得更整洁了一点(尽管某个对 原型机/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');

我自己需要这个功能,但这里的功能都不能满足我的需要。

所以我用了 Orion 的代码,改了它。

我添加了一个最小高度,这样在破坏它不会变得太小。

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

下面是 原型机版本的文本区域大小调整,它不依赖于文本区域中的列数。这是一个优越的技术,因为它允许您通过 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);
});
});

这是 Jeremy 在6月4日发布的 Prototype 插件的扩展:

如果在文本区域中使用限制,它将阻止用户输入更多字符。它检查是否有字符留下。如果用户将文本复制到文本区域,文本将被最大限度地切断。长度:

/**
* Prototype Widget: Textarea
* Automatically resizes a textarea and displays the number of remaining chars
*
* From: http://stackoverflow.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'));
}
});

对其中一些答案的一个改进是让 CSS 完成更多的工作。

基本路线似乎是:

  1. 创建一个容器元素来保存 textarea和一个隐藏的 div
  2. 使用 Javascript,使 textarea的内容与 div的内容保持同步
  3. 让浏览器来计算这个 div 的高度
  4. 因为浏览器处理呈现/调整隐藏 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;
}
<div class="textarea-container">
<textarea id="textArea"></textarea>
<div id="textCopy"></div>
</div>

Internet Explorer、 Safari、 Chrome 和 歌剧用户需要记住在 CSS 中明确设置 line-height 值。我使用一个样式表为所有文本框设置初始属性,如下所示。

<style>
TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>

下面是我刚用 jQuery 编写的一个函数,你可以把它移植到 原型机,但是它们不支持 jQuery 的“活性”,所以 Ajax 请求添加的元素不会响应。

这个版本不仅扩展,而且在按删除或退格键时收缩。

这个版本依赖于 jQuery 1.4.2。

享用;)

Http://pastebin.com/sukebtnx

用法:

$("#sometextarea").textareacontrol();

或者(例如任何 jQuery 选择器)

$("textarea").textareacontrol();

它已经在 Internet Explorer 7/Internet Explorer 8,Firefox 3.5和 Chrome 上进行了测试,一切正常。

你可浏览以下连结: 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
});
});

下面是 JQuery的一个解决方案:

$(document).ready(function() {
var $abc = $("#abc");
$abc.css("height", $abc.attr("scrollHeight"));
})

abcteaxtarea

@ memical 有一个非常棒的解决方案,可以用 jQuery 在页面加载时设置文本区域的高度,但对于我的应用程序,我希望能够随着用户添加更多内容而增加文本区域的高度。我用以下方法构建了 Memical 的解决方案:

$(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 插件。)

就像@memical 的答案。

不过我发现了一些改进。可以使用 jQueryheight()函数。但要注意填充顶部和填充底部像素。否则你的纹理会长得太快。

$(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);
});
});

我做了一个很简单的东西。首先,我将 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 的高度。

使用 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>

我的不使用 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
}

也许是最简单的解决办法:

jQuery(document).ready(function(){
jQuery("#textArea").on("keydown keyup", function(){
this.style.height = "1px";
this.style.height = (this.scrollHeight) + "px";
});
});

这样你就不需要任何隐藏的 div 或类似的东西。

注意: 您可能必须使用 this.style.height = (this.scrollHeight) + "px";,这取决于您如何设置文本区域(行高、填充和类似的东西)。

对于那些正在为 IE 编码并遇到这个问题的人。IE 有一个小技巧,使它100% CSS。

<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>

您甚至可以为 rows = “ n”提供一个值,IE 会忽略这个值,但是其他浏览器会使用这个值。我真的很讨厌实现 IE 黑客技术的代码,但是这个非常有帮助。有可能它只能在 Quirks 模式下工作。