[React] ページの下までスクロールされたことを検知する方法
最近Reactでページの下までスクロールされたことを検知し、何かしらの処理をするような実装をしました。今回はその方法を書いていきます。
なぜページの下までスクロールされたことを検知する必要が生じた?
開発中のチャイブンという中国語学習アプリには左下の方に固定でずっと表示されるホームボタンがあります。(下記画像参照)
Twitterの投稿ボタンみたいな感じですね。position: fixed
とbottom: 25px
を指定し、下から25pxの位置に固定されるようにしています。
最近このアプリにフッターを追加しました。フッターは最初は画面には表示されておらずスクロールして下まで行くと表示されます。しかし、困ったことに左下に固定していたホームボタンがフッターと重なるようになってしまいました。。
こんな感じです↓
これを治すためにページの下までスクロールされたことを検知する必要が生じたのです。
解決法
スクロール位置を検知し、表示されているフッターの高さだけホームボタンの位置も上に行くようにしました。
フッターが5pxだけ表示されていればホームボタンの位置も5px上になるようなイメージです。
解決法詳細
state作成
まずは以下を追加し、25pxを指定していたbottomをstateで持つようにしました。default値として25を入れています。
const [bottom, setBottom] = useState(25);
stateのbottomを適切に更新する関数作成
次に、スクロール位置を検出しstateのbottomの値を変更するchangeBottom
という関数を作成しました
const changeBottom = useCallback(() => {
const bottomPosition = document.body.offsetHeight - (window.scrollY + window.innerHeight);
if (bottomPosition < 55) {
setBottom(25 + 55 - bottomPosition);
}
}, []);
このコードにある値の説明は↓をご覧下さい。
名称 | 説明 |
---|---|
document.body.offsetHeight | ページ全体の高さ(スクロールしないと見えない部分も含む) |
window.innerHeight | 画面の高さ(スクロールしないと見えない部分は含まない) |
window.scrollY | スクロール量 |
55 | footer要素の高さ |
※ どれも単位はpxです。
bottomPositionが55より小さくなったらフッターが見え始めているということです。
フッターが見え始めてからホームボタンの位置を一気に55px上にしても良いのですが、それだとゆっくりスクロールした時にホームボタンがかなり上に行ってしまいますし、少し動きがカクカクしてしまいます。
なので setBottom(25 + 55 - bottomPosition)
としてフッターの見えている部分の高さのみstateのbottomにプラスしていくようにしました。最終的に全部見えた時には55pxプラスされるようになっています。
イベント登録
今の状態だとまだchangeBottomが誰にも呼ばれないので、以下を追加しスクロールイベントが発生するとchangeBottomが実行されるようにします。
useEffect(() => {
window.addEventListener('scroll', changeBottom);
return () => window.removeEventListener('scroll', changeBottom);
}, []);
後はstateのbottomを使ってホームボタンの要素のbottomを指定すれば完成です。
左下に固定していたホームボタンがフッターと重なって表示されることは無くなりました。
サイトにアクセスして確認してみてください。
終わりに
他に良い方法がありましたら是非コメントで教えてください。
Discussion