🔍

ResizeObserver API を使って要素のリサイズを検知する

3 min read

TypeScript ボタンや倍率ボタンをクリックして要素のリサイズを検知していることをご確認ください

はじめに

  • ResizeObserver API (MDN) を利用して HTML 要素のリサイズを検知します
  • React + TypeScript を使っていますが適宜 Vue などで読み替えてください
  • ただし IE はダメです

https://developer.mozilla.org/ja/docs/Web/API/ResizeObserver

element.addEventListener('resize') ?

つぎのコードは動きません。

app.ts
const element = document.getElementById('element');

element?.addEventListener('resize', () => console.log('resize!'));

なぜなら resize イベントは Window オブジェクトにしか存在しないからです。
ウィンドウ全体ではなく、特定の一要素(ドロワーなど)のリサイズを検知したい場合には使えません。

ResizeObserver API

MDN では「これは実験的な機能です。」と表示されていますが、現在では IE をのぞく主要なブラウザでサポートされています (Can I use)。

構文

var ResizeObserver = new ResizeObserver((entries, observer) => {
  /** do something in this callback */
});
  • entries は、 ResizeObserverEntry オブジェクトの配列です。変更後の要素の寸法にアクセスできます
  • observer は、 ResizeObserver 自身への参照です。なんらかの理由でコールバック内でアクセスしたいときに利用します。省略可能です

典型的な利用例


const element = document.getElementById('element');

// コンストラクタとコールバック
const observer = new ResizeObserver((entries) => {
  // 変更後の要素の width と height を取得
  console.log(`width: ${entries[0].contentRect.width}`);
  console.log(`height: ${entries[0].contentRect.height}`);
});

if (element) {
  // 要素のリサイズを監視
  observer.observe(element);
}

if (/** 一定の条件下で */) {
  // リスナーを切断する
  observer.disconnect();
}

React Hooks での使用例

App.tsx
const App: React.FC = () => {
  const containerRef = useRef<HTMLDivElement>(null);
  const statusRef = useRef<HTMLHeadingElement>(null);

  useEffect(() => {
    // コンストラクタとコールバック
    const resizeObserver = new ResizeObserver((entries) => {
      const width = entries[0].contentRect.width;
      const height = entries[0].contentRect.height;

      if (statusRef.current) {
        statusRef.current.textContent = `width: ${width}, height: ${height}`;
      }
    });

    // 要素を監視
    containerRef.current && resizeObserver.observe(containerRef.current);

    // クリーンアップ関数で監視を解く
    return (): void => {
      resizeObserver.disconnect();
    };
  }, []);

  return (
    <div className="container" ref={containerRef}>
      <h3 ref={statusRef}></h3>
    </div>
  );
};

TypeScript で利用する場合(おまけ)

標準で用意されている lib では型定義が存在しないため、別途 @types/resize-observer-browser をインストールする必要があります。

shell
$ npm install --save-dev @types/resize-observer-browser

// または

$ yarn add -D @types/resize-observer-browser

https://www.npmjs.com/package/@types/resize-observer-browser

Discussion

ログインするとコメントできます