やりたかったこと
動的生成したTextarea群(Twitterのようなもの)について、textareaの内容のscrollHeightによって、生成時点で高さを自動調整したかった。
作りたい関数の流れ
- 対象のテキストエリアを取得する
- すべての要素に対してループ
- テキストエリア1つ1つに対して最低行数を設定したい
- scrollHeightを取得して、テキストエリアから溢れていれば大きくし、逆に余っていれば小さくしてscrollHeightに合わせたい
問題点と解決法
動的生成の件
- 生成した時点で一旦調整したかったが、
$(document).on()
ではそもそもイベントが発生しないので無理。
- 生成後に関数を実行することに。
scrollHeight
-
display:none;
だとscrollHeightを取得できない。- 取得してから
display:none;
する。
- 取得してから
- javascriptネイティブなら、
textareaオブジェクト.scrollHeight
でOK -
$(セレクタ).scrollHeight
はなぜか動かない。
-
$(セレクタ).get(0).scrollHeight
とする。(オブジェクトが単体でもこうしないと動かない)
- テキストエリア生成時、内容が1行分に収まる場合でも、なぜか2行になってしまう。
- テキストエリアにはデフォルトでrows=2, cols=20が設定されているようだ。
- そもそもscrollHeightというのはlineHeightにrowsを掛けたものである。
- すると、scrollHeightを取得しても、lineHeight1とならず、lineHeight2となってしまう。
- 1行まで小さくしたいテキストエリアには、rows=1を設定しておく必要がある。
- 5行の内容を削って3行にした場合などに、小さくなってくれない。
- scrollHeightは内容の高さを見るのではなく、表示領域全体の高さを参照しているようだ。
- おそらく、5行分に大きくした時にrowsが5に更新されているためである。内容を削ってもrowsは小さくならないのでscrollHeightも減らない。
- 一旦テキストエリアを小さくしてわざと溢れさせてから(rowsを変更してもいいかも?)、scrollHeightを取得する。
lineHeight
- javascriptネイティブだと、Textareaオブジェクト、もしくはElementオブジェクトにはlineHeightがない。
- CSSで指定している場合、
オブジェクト.style.lineHeight
では取得できない。 - DOMに
style="line-height:**px"
が直接書かれていれば取れる。
最終的なコード
jQueryの場合
const adjust_textarea = (tab) => {
//jquery
const $target = $("#"+tab+"_data_area textarea");
$target.each((i,elem) => {
//最低高さ設定
let minheight;
const lineheight = parseInt($(elem).css("line-height").split("px")[0]);
if($(elem).hasClass("ta_rows1")) minheight = lineheight;
else if($(elem).hasClass("ta_rows2")) minheight = lineheight * 2;
else minheight = lineheight * 3;
//高さ変更
$(elem).height(minheight); //scrollHeightはheightに満たない場合はheightが返るので一旦最小にしてあふれさせる
const scrollheight = $(elem).get(0).scrollHeight; //lineheight * 行数が入る
if(scrollheight > minheight) $(elem).height(scrollheight);
});
};
Javascriptネイティブの場合(却下)
const taList = document.querySelectorAll("#"+tab+"_data_area textarea");
const length = taList.length;
if(0) for(let i=0; i<length; i++) {
const scrollheight = taList[i].scrollHeight; //javascriptのscrollHeightは、rowsにline-heightを掛けたもの
if(scrollheight > minheight) {
if(scrollheight > taList[i].clientHeight) {
taList[i].style.height = (scrollheight+2) + "px"; //style.heightはborder含む
} else {
taList[i].style.height = (minheight+2) + "px";
if(scrollheight > taList[i].clientHeight) {
taList[i].style.height = (scrollheight+2) + "px";
}
}
} else {
taList[i].style.height = (minheight+2) + "px";
}
}