テキスト入力時にテキストエリアの高さを自動変更

私は通常、サーバー側のプログラミングをphpで行いますが、ときどき外に出て、レイアウト、スタイル、javascriptを詳しく調べます。 最近、私はさまざまなオブジェクトにコメントを入力するときにtextareaの高さを変更する仕事をしました。 インターネット上では、これについて多くの資料はありませんでした。 一見、Vkontakte、Facebook、MyKrugなどの大規模ネットワークに実装されているソリューションに急いで行きました。 ただし、決定の際には多くの障害があり、ブラウザ間の互換性にはほど遠いものでした。







ソリューションオプションは異なっていました。

* scrollHeightおよびoffsetHeightプロパティに依存

*テキストの解析に使用される行数を計算します

*または、上記のネットワークのアイデアを使用します。



最後の選択肢はそのようなソリューションでした。 非表示レイヤー(div)が同じ幅、フォント、フォントサイズ、インデントでtextareaに作成され、新しく変更されたテキストが非表示レイヤーにコピーされ、レイヤーの高さが認識され、この高さがtextareaに設定されます。 簡単に聞こえますが、実装の過程で多くの落とし穴がありました。

現在の実装ではプロトタイプバージョン1.7を使用していますが、以前のバージョンでも同じことを行います(JQueryに置き換えるか、フレームワークを完全にカットできます)。



<!doctype><html><head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

<title>Auto-size TextArea Demo</title>

<script type="text/javascript" src="/js/prototype/prototype.js"></script><script>

function resizeArea(text_id, minHeight, maxHeight)

{

var area = $(text_id);

var area_hidden = $(text_id + "_hidden");

var text = '';

area.value.replace(/[<>]/g, '_').split("\n").each( function(s) {

text = text + '<div>' + s.replace(/\s\s/g, ' &nbsp;') + '&nbsp;</div>'+"\n";

} );

area_hidden.innerHTML = text;

var height = area_hidden.offsetHeight + 15;

height = Math.max(minHeight, height);

height = Math.min(maxHeight, height);

area.style.height = height + 'px';

}

</script><style>

body, textarea {

font-family: Tahoma, Arial, 'Nimbus Sans L', sans-serif;

font-size: 13px;

}

.text {

width:700px !important;

border:1px solid #000;

}

.text .textarea_behavior{

border:0;

width:99%;

word-wrap: break-word;

}

.text textarea{

overflow:hidden;

}

.text .comment_text_hidden{

position: relative;

}

.text #comment_text_hidden{

visibility:hidden;

position: absolute;

}

</style></head><body>

<div class="text">

<div class="comment_text_hidden"><div class="textarea_behavior" id="comment_text_hidden"></div></div>

<textarea class="textarea_behavior" rows="3" id="comment_text" onkeyup="resizeArea('comment_text', 45, 450);"></textarea>

</div>

</body></html>









他の人が非常に大きい間、ソリューションは非常にコンパクトに見えるかもしれません。 一つのことは、これが私が利用できるすべてのブラウザ(FF、Ch、Op、IE7-9)で同等に機能する唯一の最終バージョンであることを確認することです。



アプローチの特徴は何ですか:textareaにどれだけのスペースが必要かを尋ねることはできません。そのため、実際にどれだけのスペースが必要かを調べられる場所にテキストを配置します(この例では、高さのみが興味深いです)。 ここには多くの落とし穴があります。 テキスト、ワードブレーク、タグ、複数のスペースのタイプと量を正確に保持するために、textareaからdivにテキストを配置する方法-一般に、プレーンテキストのように見えるものはすべてhtmlのようには見えません。 preタグを使用できませんでした。なぜなら 彼を飼いならすのはもっと大変でした。



順番に、私が遭遇したすべての落とし穴(ここでは、コードが進化しており、以前に解決された問題の一部がこのコードに現れないため、ここでいくつかの問題に言及しません)。 ここでは、コードによって解決された問題のみがわかります。







これらの問題の解決策は、コードによく反映されています。 レイヤーはtextareaのすぐ近くに隠されています。これにより、レイヤーの幅の設定について考える必要がなくなります。 いくつかのスペースの行は、ギャップ+&nbsp;に置き換えられます。 空行-<div>&nbsp; </ div>(上記のソーシャルネットワークはすべて<br>を使用していますが、成功しませんでした)。 タグは非常に簡単にエスケープされます。文字<and>は_に置き換えられます。 さて、私にとって最も興味深い発見は、連続したテキストをワードラップスタイルで分割することです:break-word;。

さて、このアイデアで最も重要なことは、レイヤーとテキストエリアのスタイルが完全に一致することです。



他のアプローチの欠点



1. scrollHeightプロパティとoffsetHeightプロパティに依存することが、私が実装した最初のオプションです。 すべて問題ありませんが、ここでtextareaのサイズを小さくすることはできません。



2.テキストの解析に使用される行数を計算します。 2番目のオプション。 これはすでに優れていますが、判明したように、すべての文字が同じ幅であるtextareaにMonospaceタイプのフォントをインストールすることによってのみ使用できます。 これが通常の精度を達成する唯一の方法です。 しかし、これはデザイナーのアイデアに反しています...



好奇心the盛な人(resizeArea関数の一部)のコードは次のとおりです。



var linecount = 1;

area.value.split("\n").each( function(s) {

linecount += Math.floor( s.length / cols ) + 1;

} )

area.rows = linecount;









行とプラス行をカウントします。 colsパラメータを知る必要があるだけです-これはまさに私たちが知っていることであり、Monospaceフォントなしでは不可能です。 文字の数Wとiを比較すると、行にはまったく異なる数が含まれています。



結果



行われた作業の結果は上記のとおりです。 FF、Ch、Op、IE7-9で動作します。 皆さんのお役に立てばと思います。 すべての種類のオプションを実装した後、私は本当にすべてのブラウザーのギニア向けの単体テストを望んでいました...



興味深い資料


CSSを使用して長いリンクと連続テキストを転置する

テキストエリアの自動サイズ設定

jQuery autoResize



All Articles