今回は、スマホファーストなウェブサイトやアプリが多く出てくる中、
当たり前のように見かけるようになった2つの機能。
- 上スワイプでローディング
- 下スワイプでリフレッシュ
すごくメジャーな機能ですが、
・Javascriptで上下スワイプ操作の実装方法を知りたい
・上下スワイプによる機能の切り分けの仕組みを知りたい
・ライブラリを使用せずに実装してみたい
こんな悩みあるんじゃないでしょうか。
むしろ当たり前になりすぎた機能ほど素朴な疑問は解決されていないんじゃないでしょうか。
今回はそんな悩みを解決すべく、
Javascriptを使って機能の実装をしながら詳細の説明をしていきます。
ライブラリを使用すると、数十行のコードで実装ができてしまう機能ですが、
一度プレーンなJavascriptのみで仕組みを理解しながら実装することで、
ライブラリを使って実装する際によりカスタマイズの幅も広がるかと思います。
どのようにしたら実現できるかを考えてみる
機能の実装を行うためには、仕組みを理解する必要があります。
仕組みを理解したあとは、仕組みを動かすために必要な要素を洗い出していきます。
上スワイプでローディング
上スワイプでローディングは、
ページの最後に到達したもしくはページの最後に到達しそうなタイミングで
処理が行われます。
では、このページの最後に到達したもしくはページの最後に到達しそうというのはどのように判定するかを考えます。
後続の説明の為命名をしておきます。
overHeight | スマホ画面トップからはみ出た高さ |
clientHeight | スマホ画面の高さ |
scrollHeight | 未表示部分を含めたスクロール可能な高さ |
WEBコンテンツ(薄い黄色部分)の最後に到達したことを判定する公式を考えてみます。
overHeight + clientHeight ≧ scrollHeight
では続いて、もう少しで到達しそうなことを判定する公式を考えてみます。
もう少しで到達の定義をscrollHeightのbottomまで25pxだとします。
overHeight + clientHeight ≧ scrollHeight - 25
ここまでくればローディングトリガーの発火条件を書くのは、
公式リファレンスを見て3つの要素をどのように取得するかを調べるだけですね。
let overHeight = document.documentElement.scrollTop;
let clientHeight = document.documentElement.clientHeight;
let scrollHeight = document.body.scrollHeight;
const distance = 25
if (overHeight + clientHeight >= scrollHeight - distance){
// ローディング処理を書いていく
};
下スワイプでリフレッシュ
下スワイプでリフレッシュは、
WEBコンテンツのTOPがスマホ画面のTOPに位置している時に、
画面の下スワイプ操作を開始すると、リフレッシュを連想させるローディングアイコンを表示させ、
一定距離下スワイプするとリフレッシュ処理が行われます。
では、この下スワイプ操作の開始と一定距離下スワイプしたというのをどのように判定するかを考えます。
後続の説明の為命名をしておきます。
startPosition | スワイプ開始位置(タップ位置) |
endPosition | スワイプ終了位置(指が画面から離れた位置) |
swipeDistance | タップ状態で指を移動させた距離 |
startPositionは画面がタップされたときにYの座標を確認すれば取得できそうです。
(ちなみにY座標を取得するのは上下移動距離を計算するためです)
swipeDistanceは指が移動した時のY座標からstartPositionを引いてあげれば取得できそうです。
endPositionは画面から指が離れた時のY座標を確認すれば取得できそうです。
下スワイプリフレッシュはコード量が多めなので、全体を見せながらコメントで説明していきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>swipe down</title>
</head>
<body>
<main>
<section id="refreshContainer" style="height:100vh;">
// 画面どこをスワイプしても反応するようheight:100vhを設定しています。
<p class="refreshText"></p>
<p>sample text</p>
<p>sample text</p>
<p>sample text</p>
<p>sample text</p>
<p>sample text</p>
<p>sample text</p>
</table>
</div>
</main>
</body>
<script>
// 変数定義
let container = document.getElementById('refreshContainer'),
refreshText = document.querySelector('.refreshText'),
// 本来はrefreshIconを表示させますが、今回はテキストで代替します。
startPosition = 0,
swipeDistance = 0;
// 画面タップ時の監視
container.addEventListener('touchstart', function (e) {
startPosition = e.touches[0].pageY;// タップされたY座標を取得
container.style.position = 'relative';
container.style.transition = 'transform 0s';
}, false);
// 移動時の監視
container.addEventListener('touchmove', function (e) {
swipeDistance = e.touches[0].pageY - startPosition;// 現在の指のY座標 - 開始位置
console.log(swipeDistance)
if (swipeDistance > 20 && swipeDistance < 60) {
refreshText.innerText = '下にスワイプしてリフレッシュ';
container.style.transform = 'translateY(' + swipeDistance + 'px)';
}
if (swipeDistance >= 60) {
refreshText.innerText = '離してリフレッシュ';
}
}, false);
// 指を離したときの監視
container.addEventListener('touchend', function (e) {
// 最終位置からstartPositionを引いて移動距離を計算
swipeDistance = e.changedTouches[0].pageY - startPosition;
// 移動距離が60px以上の場合、更新処理実施
if (swipeDistance >= 60) {
refreshText.innerText = '更新処理中';
//更新処理を記述、今回は1秒後にrefreshContainerを呼び出し初期状態に戻す
window.setTimeout(refreshContainer, 1000);
} else {
container.style.transition = 'transform 0.5s';
container.style.transform = 'translateY(0px)';
refreshText.innerText = '';
}
}, false);
function refreshContainer() {
container.style.transition = 'transform 0.5s';
container.style.transform = 'translateY(0px)';
refreshText.innerText = '';
};
</script>
</html>
さいごに
スマホファーストの時代では必須機能でもある、
「上スワイプローディング」「下スワイプリフレッシュ」
を今勢いのあるプログラミング言語Javascriptでライブラリを使わずに実装をしてみました。
1歩づつ考えていくと難易度はそれほど高くなかったのでは無いでしょうか。
ライブラリが充実している今、なかなか0➔1の開発をする機会が少ないですが、
仕組みを考えてプログラムを0から書いていくのも、
エンジニアという職業の1つの楽しみだと思います。
同じような考えを持ったエンジニアたちが0➔1開発をするときの設計の参考にでもなったら嬉しいです。