좋은 라이브러리가 있다.
npm: https://www.npmjs.com/package/react-pageflip
github: https://github.com/Nodlik/StPageFlip
doc: https://nodlik.github.io/StPageFlip/docs/index.html#point
다른 라이브러리로는 react-flip-page https://www.npmjs.com/package/react-flip-page
책넘기는 애니메이션이 잘만들어져 있고 실제 마우스나 모바일 디바이스에선 터치로 flip 가능하다.
그러나 구현 중 클릭하면 페이지가 넘어가는 게 짜증나서 disableFlipByClick
를 true로 줬다
글자를 클릭하면 이벤트도 줘야해서 disabled 처리를 하는 게 좋았다.
페이지 귀퉁이에 있는 글자에 마우스 커서를 올리려고 하면 페이지 귀퉁이가 말려올라와서 showPageCorners
도 false를 해줬다
문제 될것이 없어보였다
귀퉁이에 있는 글자를 클릭하면 이벤트도 발생하지만 다음 페이지로 넘어가 버리는 오류가 있었다
클릭이벤트를 분명 disabled 처리 했을텐데??
공식문서를 다시 잘보니 이런 게 있었다.
코너를 클릭하면 또 넘어가게 해놨나 보다
빌어먹을
글자 클릭 시 일어나는 버블링을 막어보려고 했지만 잘 안됐다. pageFlip 라이브러리의 랜더 방식에 차이가 있는 모양이었다.
별 수 없이 useMouseEvents
:마우스나 터치 이벤트 사용여부 option 이다. false 처리 해줬다
이제 책넘기는 애니메이션만 제공하는 라이브러리, 손가락이나 마우스로 책 넘기듯이 Flip 이벤트를 주는 것은 불가능한 상태가 됐다.
그러나, javascript는 못할게 없다.
html은 mouseDown, mouseUp, touchStart, touchEnd method가 있으니 이걸로 포인트 좌표값 계산해서 책넘기는 효과를 줄 것이다.
그 전에 먼저 FlipPage 인스턴스에 접근해서 페이지 넘기는 함수를 만든다..
const handleGoPrev = () => {
if (isMobile) {
bookIns.turnToPrevPage();
} else {
bookIns.flipPrev();
}
};
const handleGoNext = () => {
bookIns.flipNext();
};
몰랐는데 disableFlipByClick 를 true로 하면 모바일에서 flipPrev가 안먹는다. 앞으로 안가는 기이형상. 그런데 또 turnToPrevPage()는 된다. 둘의 차이는 애니메이션이 있,냐 없냐의 차이다. 라이브러리를 좀 잘못 만든 것 같다. 지금이라도 라이브러리 바꿔볼까 싶지만 끝까지 가보겠다
//** mouse event
const [mdX, setMdX] = useState<number>(0);
const [mdY, setMdY] = useState<number>(0);
const [muX, setMuX] = useState<number>(0);
const [muY, setMuY] = useState<number>(0);
//** touch event
const [tcX, setTcX] = useState<number>(0);
const [tcY, setTcY] = useState<number>(0);
좌표값을 저장할 상태를 만들어준다.
mouseDown,mouseUp 이벤트는 모바일에선 안먹으니 Touch 값을 저장할 상태도 만든다
const handleMouseDownStart = (
e: React.MouseEvent<HTMLElement>
) => {
setMdX(e.clientX);
setMdY(e.clientY);
};
const handleMouseDownEnd = (e: React.MouseEvent<HTMLElement>) => {
setMuX(e.clientX);
setMuY(e.clientY);
};
useEffect(() => {
const dragSpaceX = Math.abs(mdX - muX);
const dragSpaceY = Math.abs(mdY - muY);
const vector = dragSpaceX / dragSpaceY;
if (mdX !== 0 && dragSpaceX > 100 && vector > 2) {
if (muX < mdX) {
handleGoNext();
} else if (muX > mdX) {
handleGoPrev();
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [muX]);
const handleTouchStart = (e: React.TouchEvent) => {
console.log(e.changedTouches[0].pageX);
setTcX(e.changedTouches[0].pageX);
setTcY(e.changedTouches[0].pageY);
};
const handleTouchEnd = (e: React.TouchEvent) => {
const distanceX = tcX - e.changedTouches[0].pageX;
const distanceY = tcY - e.changedTouches[0].pageY;
const vector = Math.abs(distanceX / distanceY);
if (distanceX > 30 && vector > 2) {
handleGoNext();
} else if (distanceX < -30 && vector > 2) {
handleGoPrev();
}
};
이제 이 함수들을 HTML 안에 넣어주면 된다
return (
<HTMLFlipBook
{...options}
className={`h-3/4 stf__parent ${zoom && "opacity-0"}`}
ref={bookRef}
>
{pages.map((el, idx) => (
<div
key={idx}
className="bg-white lg:overflow-hidden"
dangerouslySetInnerHTML={{ __html: el.innerHTML }}
onClick={onClick}
onMouseDown={mdStart}
onMouseUp={mdEnd}
onTouchStart={tcStart}
onTouchEnd={tcEnd}
/>
))}
</HTMLFlipBook>
);
다음은 블로그 페이지네이션 만들거다ㅎㅎ