はじめに
モバイル用のwebアプリを作成していまして、 リロードされると色々と困ると思ったのでせめてスクロールリロードは禁止にしようと思い作りました。その時に画面全部のスクロール禁止は簡単だけど、一部分のスクロール許可は大変だなと思ったのでメモです。
※一部分のスクロール許可コンポーネントはコンボボックスには対応していません。
完成したコンポーネント・CSS
画面全部のスクロール禁止処理コンポーネントAllScrollLock.jsx
import React, { useEffect, useCallback } from "react";
const AllScrollLock= React.memo(() => {
/**
* イベントリスナーの設定
*/
useEffect(() => {
// モバイルスクロール禁止処理
document.addEventListener("touchmove", scrollNo, { passive: false });
return () => {
// イベントの設定解除
document.removeEventListener("touchmove", scrollNo);
};
}, []);
/**
* モバイルスクロール禁止処理
*/
const scrollNo = useCallback((e) => {
e.preventDefault();
}, []);
return <></>;
});
export default AllScrollLock;
一部分スクロール許可のコンポーネント
AllowPartialScrolling.jsx
import React, { useEffect, useRef, useCallback } from "react";
const AllowPartialScrolling= React.memo((props) => {
// スクロール可能DOM格納
const scrollArea = useRef(null);
useEffect(() => {
scrollArea.current = document.getElementById("scroll_item");
scrollArea.current.scrollTop = 1;
// モバイルスクロール禁止処理
window.addEventListener("resize", setFillHeight);
window.addEventListener("touchmove", scrollNo, { passive: false });
scrollArea.current.addEventListener("focusout", onFocusOut);
scrollArea.current.addEventListener("scroll", scrollControl);
scrollArea.current.addEventListener("touchstart", touchHandler, {
passive: false,
});
return () => {
// イベントの設定解除
window.removeEventListener("resize", setFillHeight);
window.removeEventListener("touchmove", scrollNo);
scrollArea.current.removeEventListener("focusout", onFocusOut);
scrollArea.current.removeEventListener("scroll", scrollControl);
scrollArea.current.removeEventListener("touchstart", touchHandler);
};
}, []);
/**
* 高さを調整する処理
*/
const setFillHeight = useCallback(() => {
window.scroll(0, 0);
}, []);
/**
* モバイルスクロール禁止処理
*/
const scrollNo = useCallback((e) => {
if (
e.target.closest("#scroll_item") === scrollArea.current &&
scrollArea.current.scrollTop !== 0 &&
scrollArea.current.scrollTop + scrollArea.current.clientHeight !==
scrollArea.current.scrollHeight
) {
e.stopPropagation();
} else {
e.preventDefault();
}
}, []);
/**
* ピンチズームをしない処理(2本指で操作させないようにする)
*/
const touchHandler = useCallback((event) => {
if (event.touches.length > 1) {
event.preventDefault();
}
}, []);
/**
* フォーカスアウトした時の処理
*/
const onFocusOut = useCallback(() => {
window.scroll(0, 0);
}, []);
/**
* スクロールリロードさせない処理
*/
const scrollControl = useCallback(() => {
if (scrollArea.current.scrollTop === 0) {
scrollArea.current.scrollTop = 1;
} else if (
scrollArea.current.scrollTop + scrollArea.current.clientHeight ===
scrollArea.current.scrollHeight
) {
scrollArea.current.scrollTop = scrollArea.current.scrollTop - 1;
}
}, []);
return (
<div className="scroll_control" id="scroll_item">
<div className="scroll_children">{props.children}</div>
</div>
);
});
export default AllowPartialScrolling;
一部分スクロール許可のcss
scroll.css
/* モバイルスクロールローディング禁止 */
.scroll_control {
overflow-y: scroll;
height: 100vh;
-webkit-overflow-scrolling: touch;
padding: 1.5vh 0 24vh 0;
}
.scroll_children {
min-height: 100vh;
-webkit-overflow-scrolling: touch;
overflow-y: scroll;
}
実装方法
- 画面全体をスクロールする必要がない画面は画面全部のスクロール禁止処理コンポーネントをimportします。
- 画面の一部分をだけスクロールしたい画面は一部分スクロール許可のコンポーネントをimportします。
app.jsx
import React from 'react';
import AllScrollLock from "../components/test/AllScrollLock";
import Hoge1 from "../components/hoges/Hoge1";
import Hoge2 from "../components/hoges/Hoge2";
import Hoge3 from "../components/hoges/Hoge3";
// フォルダの階層は各々違うの書き換えお願いします。
export default function App(props) {
return (
<>
<Hoge1 />
<Hoge2 />
<Hoge3 />
<AllScrollLock/>
</>
);
}
使いたい所で置くだけで画面全部がスクロール禁止になります。
例:一部分のスクロール可能コンポーネント
app.jsx
import React from 'react';
import AllowPartialScrolling from "../components/test/AllowPartialScrolling";
import Hoge1 from "../components/hoges/Hoge1";
import Hoge2 from "../components/hoges/Hoge2";
import Hoge3 from "../components/hoges/Hoge3";
// フォルダの階層は各々違うの書き換えお願いします。
export default function App(props) {
return (
<>
<AllowPartialScrolling>
<Hoge1 />
<Hoge2 />
<Hoge3 />
</AllowPartialScrolling>
</>
);
}
一部分許可の場合はスクロールしたいDOMをはさむとスクロール可能になります。
大変だった部分:一部分のスクロール可能コンポーネント
- テキストボックス押下時にキーボード出現のため画面の高さが変更される部分の対応。
- cssの上下余白調整
感想
ページ事にスクロールの許可ができるよになったのでよかったです。作成している時はパッケージがないのかと思いましたが、パッケージありましたね(笑)作成後に知りました

記事:body-scroll-lock.js「すべてのブラウザでスクロールのロックしたるで」←こいつ超有能
※追記↑cssでスクロールできる場所を作成しなければいけない点は一緒でした。