慣性スクロールを想定したスクロールイベントの終了後実行
Google Chrome等でscrollのイベントを発生させた場合、スクロールが終了するまでに継続的にイベントが発生するようになっている。
これだとスクロール中のポイントごとにイベントが走るので、例えばalert()などをスクロール中に挟んでおいた際などにscrollのイベントが継続している間(始端→終端に達する間)はalert()が連続して表示されてしまう。
そもそもalert()自体をスクロールの中に組み込むことはまずないが・・・。
これが例えば、ある一定のスクロールポイントに到達した際にCSSを付与<=>削除して、ボタンを表示<=>非表示等と言った動作を行う場合にもこれらが連続して行われる。
PCの場合はホイールやカーソルキー、ページダウンorアップキーなどでスクロール量がある程度決まっているのであまり問題ないように見えるかもしれない。
ただ、iOSなどの慣性スクロールでスクロール量が一定とはいえない場合、transitionやtransform等でアニメーションを行っていようものなら、慣性スクロールの1ドットごとにCSSの付与<=>削除が実行されるため、CSSのtransitionやtransformに指定したアニメーションが実行されない結果となってしまう。
それを解消するため、遅延制御のセットとリセットを入れてやれば良いのでは?と思い、以下のコードを作った。
var timeout = new Object(); $(window).bind('scroll', function(){ clearTimeout(timeout); timeout = setTimeout(function(){ alert('一回だけ実行'); clearTimeout(timeout); }, 100); });
timeoutはグローバル変数的なものだが、実際の組み込みではクロージャなどで内部のみで有効な変数にする。
setTimeout()によって実行を遅延してその後の動作を行わせるのは昔ながらの方法だが、4行目のsetTimeout()の前に、3行目のclearTimeout()を入れてtimeout変数の時間をクリアするのがミソ。
こうすることでスクロール中は常にtimeout変数をリセットし、その次に指定したsetTimeout()の実行内容をスクロールが動いている間は常に破棄する。
そして、スクロールが完全に終わったときに最後のsetTimeout()だけを残して実行を行う。
setTimeoutで指定するフレームは0.1秒まで確認した。
しかし、指定したフレームは慣性スクロールが1ドットごとに動くカンマレベルの時間を下回ってしまうと、やはり上記のコードを組み込まない状態と同じになるので注意。