サイトを作っていると、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
などとするとサイズが取得できます。
まとめ
リサイズの処理はリサイズマネージャにまかせて、肝心の処理内容は別に記述することで、コードが綺麗になった気がします。な、なってるよね……。
「ブラウザの動き」といった画面全体の処理を外部化するのが目的だったので、同じ考え方でブラウザのスクロールを監視する「スクロールマネージャ」のようなものも作れると思います。
「もっと良い書き方があるぞ」という場合は是非教えていただければ幸いです。