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

私は通常、サーバー側のプログラミングを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

Source: https://habr.com/ru/post/J114182/


All Articles