LINEみたいに要素が追加されたら自動で下までスクロールさせる

公開:2021/02/04
更新:2021/02/04
2 min読了の目安(約2600字TECH技術記事

概要

やりたいこと

  • LINEのように最新アイテムが一番下に追加されていくチャットのようなUIで、アイテムが追加されたら自動で下までスクロールしてほしい
  • 且つ、過去のチャットを見ている(一番下にスクロールされていない)状態の時は自動ではスクロールしない

注釈

  • 実際に書いた時はRiot.jsとかPugとか使って書いていたのでもう少し簡潔ではありますが、大まかにはやっていることは一緒なので参考になれば

実際にやってみた

https://runstant.com/supermuscles/projects/e808e8b2

コード

index.html
index.html
    <form id="form" action="" method="get" accept-charset="utf-8">
      <input type="text" name="input" id="input" value="" />
      <button id="button" type="submit">追加</button>    
    </form>
    <div id="container" class='container'>
    </div>
main.css
main.css
  .container {
    height: 300px;
    background-color: gray;
    overflow: scroll;
    padding: 2px 4px;
  }

  .child {
    height: 55px;
    width: 90%;
    background-color: white;
    border: 1px black solid;
    border-radius: 8px;
    margin-bottom: 4px;
  }
main.js
main.js
  window.onload = function() {
    var form = document.getElementById('form');
    var input = document.getElementById('input');
    var container = document.getElementById('container');
    
    // チャットを追加する
    var addChat = () => {
      var text = input.value;
      var div = document.createElement("div");
      div.innerText = text;
      div.classList.add('child');
      container.appendChild(div);
      input.value = '';
    };
    
    // 下までスクロールする
    var scrollToBottom = () => {
      container.scrollTop = container.scrollHeight;
    };
    
    // 一番下までスクロールしているかどうか
    var isScrollBottom = () => {
      return container.scrollHeight === container.scrollTop + container.offsetHeight;
    };
    
    form.addEventListener('submit', (e) => {
      e.preventDefault();
      e.stopPropagation();
      // 一番下までスクロールされていれば追加後も一番下までスクロールする
      if (isScrollBottom()) {
        addChat();
        scrollToBottom();
      }
      // 一番下までスクロールされていなければスクロールしない
      else {
        addChat();
      }
    });
  };

解説

overflow: scroll;

  • チャットが追加されるエリアのスタイルにoverflow: scroll;を追加
  • これにより、チャットエリアがスクロールできるようになる

Element.scrollTop

  • 皆大好きMDNのElement.scrollTopを見ると、> 要素の内容が垂直にスクロールするピクセル数を取得または設定しますと書いてあり、> 任意の整数値で設定することができますとのこと
  • 任意の数値としては、> 指定された値が、コンテンツがスクロールできる最大値を超えていたら、 scrollTop は最大値に設定されますとあるので、チャットエリアのスクロール範囲の高さであるscrollHeightをいれてあげることで、一番下までスクロールしてくれる

一番下までスクロールしているかどうか

  • これは、チャットエリア全体の高さに対して、1. 見えている現在の垂直方向のスクロール値2. 見えているチャットエリア自体の大きさを足して、その値と一致するかを調べることで判定できる

まとめ

  • いつも通り、例でテキトーに作っただけなので見た目はダサいが、機能的には満たしているので一旦これで
  • あとはスクロールをアニメーションにしたり、下にスクロールしていない状態で新しいアイテムが追加されたら矢印アイコンを出す等すれば、いい感じにチャットになりそう