LoginSignup
1
1

More than 3 years have passed since last update.

[Javascript] Textareaの高さを自動調整しようとしてだいぶハマった件についてのメモ

Posted at

やりたかったこと

動的生成したTextarea群(Twitterのようなもの)について、textareaの内容のscrollHeightによって、生成時点で高さを自動調整したかった。

作りたい関数の流れ

  • 対象のテキストエリアを取得する
  • すべての要素に対してループ
    • テキストエリア1つ1つに対して最低行数を設定したい
    • scrollHeightを取得して、テキストエリアから溢れていれば大きくし、逆に余っていれば小さくしてscrollHeightに合わせたい

問題点と解決法

動的生成の件

  1. 生成した時点で一旦調整したかったが、$(document).on()ではそもそもイベントが発生しないので無理。
    • 生成後に関数を実行することに。

scrollHeight

  1. display:none;だとscrollHeightを取得できない。
    • 取得してからdisplay:none;する。
  2. javascriptネイティブなら、textareaオブジェクト.scrollHeightでOK
  3. $(セレクタ).scrollHeightはなぜか動かない。
    • $(セレクタ).get(0).scrollHeightとする。(オブジェクトが単体でもこうしないと動かない)
  4. テキストエリア生成時、内容が1行分に収まる場合でも、なぜか2行になってしまう。
    • テキストエリアにはデフォルトでrows=2, cols=20が設定されているようだ。
    • そもそもscrollHeightというのはlineHeightにrowsを掛けたものである。
    • すると、scrollHeightを取得しても、lineHeight*1とならず、lineHeight*2となってしまう。
    • 1行まで小さくしたいテキストエリアには、rows=1を設定しておく必要がある。
  5. 5行の内容を削って3行にした場合などに、小さくなってくれない。
    • scrollHeightは内容の高さを見るのではなく、表示領域全体の高さを参照しているようだ。
    • おそらく、5行分に大きくした時にrowsが5に更新されているためである。内容を削ってもrowsは小さくならないのでscrollHeightも減らない。
    • 一旦テキストエリアを小さくしてわざと溢れさせてから(rowsを変更してもいいかも?)、scrollHeightを取得する。

lineHeight

  1. javascriptネイティブだと、Textareaオブジェクト、もしくはElementオブジェクトにはlineHeightがない。
  2. CSSで指定している場合、オブジェクト.style.lineHeightでは取得できない。
  3. 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";
        }
    }

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1