サイトを作っていると、JavaScriptでウインドウのリサイズ時になにか処理をしたくなったりします。例えば、アイキャッチをブラウザのウインドウいっぱいにする、とか。
そういうときに、今までは普通に$(window).on('resize', () => { (ここに関数書く) });という感じで書いていました。が、「リサイズマネージャ的なものを作っとくと便利やで」と教えてもらったので、ちょっとやってみました。
考え方
- リサイズ用の関数をつくり、リサイズ時にその関数を実行する
- 関数の中に、リサイズ時に実行したい関数を入れる
- メインのJSでは、関数の追加と初期化しかおこなわない
ResizeManager.js
ResizeManager.jsがリサイズマネージャ本体です。コンストラクタ関数をのぞくと、init関数、add関数、remove関数、update関数があります。
add関数では、引数から受け取った関数をthis.functionsという配列に追加します。
remove関数では、関数を配列から削除します。
update関数では、this.functionsに入れた関数をすべて実行しています。
そして、init関数で、ウインドウのリサイズ(と画面回転)時にupdate関数を実行しています。リサイズイベントが発生しまくるのを防ぐため、window.requestAnimationFrameを使ってイベントを間引いています。window.requestAnimationFrameが使えない古いブラウザなどではsetTimeoutを使うようにしています。
参考:高頻度で発生するブラウザイベントのイベントリスナー呼び出し最適化 - kitak.blog
'use strict';
window.jQuery = window.$ = require('jquery');
export default class ResizeManager {
constructor() {
this.$window = null;
this.windowWidth = 0;
this.windowHeight = 0;
this.functions = [];
this.length = 0;
this.fps = 60;
this.isRunning = false;
}
init() {
this.$window = $(window);
this.update();
this.$window.on('resize orientationchange', () => {
if (!this.isRunning) {
this.isRunning = true;
if (window.requestAnimationFrame) {
window.requestAnimationFrame(() => {
this.update();
});
} else {
setTimeout(() => {
this.update();
}, 1000/this.fps);
}
}
});
}
add(func) {
this.functions.push(func);
this.length = this.functions.length;
}
remove(func) {
this.functions.splice(func, 1);
this.length = this.functions.length;
}
update() {
this.windowWidth = this.$window.width();
this.windowHeight = this.$window.height();
for (let i = 0; i < this.length; i++) {
let func = this.functions[i];
func();
}
this.isRunning = false;
}
};
main.js
main.jsが名前の通りメインのJSファイルです。これをBrowserifyなどでコンパイルして、ブラウザで実行します。
このファイルでは、前述したResizeManagerクラスをimportしてresizeManagerインスタンスを生成し、あらかじめ定義したadd関数とinit関数を実行しています。add関数の引数に、リサイズ時に実行させたい関数をセットします。
'use strict';
window.jQuery = window.$ = require('jquery');
import ResizeManager from './ResizeManager';
const resizeManager = new ResizeManager();
(() => {
$(() => {
// 関数の追加と初期化
resizeManager.add(resized01);
resizeManager.add(resized02);
resizeManager.init();
});
// 関数の定義
// ファイルを分けてimportしてもいいですね
const resized01 = () => {
console.log('is resized! 01');
};
const resized02 = () => {
console.log('is resized! 02');
};
})();
また、リサイズマネージャの中でウインドウの幅と高さを変数にセットしています。なので他の箇所でウインドウの幅と高さを取ってなんかやりたい場合は、resizeManager.windowWidthなどとするとサイズが取得できます。
まとめ
リサイズの処理はリサイズマネージャにまかせて、肝心の処理内容は別に記述することで、コードが綺麗になった気がします。な、なってるよね……。
「ブラウザの動き」といった画面全体の処理を外部化するのが目的だったので、同じ考え方でブラウザのスクロールを監視する「スクロールマネージャ」のようなものも作れると思います。
「もっと良い書き方があるぞ」という場合は是非教えていただければ幸いです。