티스토리 뷰
예제
배포 링크
https://fervent-hugle-5ea8ae.netlify.app/
필요한 것
useState, useRef, useEffect
import { useState, useRef, useEffect } from "react";
사용할 오브젝트
const WantedImg = [
"https://static.wanted.co.kr/images/banners/1489/312a0c29.jpg",
"https://static.wanted.co.kr/images/banners/1486/fba2df30.jpg",
"https://static.wanted.co.kr/images/banners/1468/3df61cbc.jpg",
"https://static.wanted.co.kr/images/banners/1490/0b775035.jpg",
"https://static.wanted.co.kr/images/banners/1484/b2853456.jpg",
"https://static.wanted.co.kr/images/banners/1460/619f3af7.jpg",
"https://static.wanted.co.kr/images/banners/1473/41f7b36e.jpg",
"https://static.wanted.co.kr/images/banners/1487/0d36f0b5.jpg",
"https://static.wanted.co.kr/images/banners/1488/baa54448.jpg",
];
const wantedTitle = [
"22년 달라지는 노동법령",
"성과를 내는 마케팅",
"해, 커리어 EP 02 공개",
"마케팅 주니어를 찾습니다",
"성장하는 개발자가 되려면?",
"개발자 성장 비결 공개!",
"개발자 되고 싶은 분들!?",
"포트폴리오를 부탁해!",
"UX 디자이너의 커리어 설계",
];
const wantedDes = [
"노무관리 쟁점 한 눈에 파악하기",
"실제 사례를 공개합니다!",
"마지막 관문 2라운드의 승자는?",
"기업 과제 풀고 취업까지 한번에!",
"OOO 검색하지 말 것!",
"Velog, 글 쓰는 개발자들의 이야기",
"프론트엔드 무료 교육과정 참여하기",
"디자이너의 포폴 살펴보기",
"브랜드 가치를 더하는 디자인",
];
1. 슬라이드 만들기
//슬라이드
const slideRef = useRef(null);
const [index, setIndex] = useState(0); // 인덱스를 만들어줍니다.
const [isSlide, setIsSlide] = useState(false); // 슬라이드 중인지 체크해줍니다. 슬라이드 중에 여러번 빠르게 클릭 못하게 하는 역할
const [x, setX] = useState(0); // css에서 슬라이드 애니메이션 효과를 주기위해 x만큼 이동시키는 역할입니다.
<Row
key={index}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
ref={slideRef}
style={{
transform: `translateX(${x}vw)`,
}}
>
<Container>
<PrivewImg
style={{
opacity: 0.5,
width: windowWidth > 1200 ? null : `80vw`,
height:
windowWidth > 1200
? null
: windowWidth < 770
? "185px"
: "250px",
}}
src={WantedImg[morePrevImg]}
></PrivewImg>
</Container>
<Container>
<PrivewImg
style={{
opacity: 0.5,
width: windowWidth > 1200 ? null : `80vw`,
height:
windowWidth > 1200
? null
: windowWidth < 770
? "185px"
: "250px",
}}
src={WantedImg[PrevImg]}
></PrivewImg>
</Container>
<ImgWrapper>
<Img
style={{
opacity: 1,
width: windowWidth > 1200 ? null : `80vw`,
height:
windowWidth > 1200
? null
: windowWidth < 770
? "185px"
: "250px",
}}
src={WantedImg[index]}
/>
{!isSlide && windowWidth > 1200 ? (
<ImgDes>
<Title>{wantedTitle[index]}</Title>
<Des>{wantedDes[index]}</Des>
<LinkSpan>
바로가기<i class="fas fa-chevron-right"></i>
</LinkSpan>
</ImgDes>
) : null}
{!isSlide && windowWidth <= 1200 ? (
<MiniWrapper>
<MiniTitle>{wantedTitle[index]}</MiniTitle>
<MiniDes>{wantedDes[index]}</MiniDes>
<LinkSpan>
바로가기<i class="fas fa-chevron-right"></i>
</LinkSpan>
</MiniWrapper>
) : null}
</ImgWrapper>
<Container>
<PrivewImg
style={{
opacity: 0.5,
width: windowWidth > 1200 ? null : `80vw`,
height:
windowWidth > 1200
? null
: windowWidth < 770
? "185px"
: "250px",
}}
src={WantedImg[NextImg]}
></PrivewImg>
</Container>
<Container>
<PrivewImg
style={{
opacity: 0.5,
width: windowWidth > 1200 ? null : `80vw`,
height:
windowWidth > 1200
? null
: windowWidth < 770
? "185px"
: "250px",
}}
src={WantedImg[moreNextImg]}
></PrivewImg>
</Container>
</Row>
총 5개의 화면을 구성하고 클릭을 할 때마다 인덱스가 줄거나 커짐에 따라 화면을 구성하는 텍스트와 이미지를 배열순서를 이용하여 슬라이드처럼 이미지가 변하도록 하였습니다.
const increaseClick = async () => {
if (isSlide) {
return;
}
setX(-56);
setIsSlide(true);
await setTimeout(() => {
setIndex((prev) => (prev === 8 ? 0 : prev + 1));
setX(0);
setIsSlide(false);
}, 500);
//setIndex((prev) => (prev === 7 ? 0 : prev + 1));
};
const decreaseClick = async () => {
if (isSlide) {
return;
}
setX(+56);
setIsSlide(true);
await setTimeout(() => {
setIndex((prev) => (prev === 0 ? 8 : prev - 1));
setX(0);
setIsSlide(false);
}, 500);
};
const morePrevImg = index === 1 ? 8 : index === 0 ? 7 : index - 2;
const PrevImg = index === 0 ? 8 : index - 1;
const NextImg = index === 8 ? 0 : index + 1;
const moreNextImg = index === 8 ? 1 : index === 7 ? 0 : index + 2;
//console.log(slideRef.current);
//console.log(index);
const Wrapper = styled.div`
margin: 22px 0px;
display: flex;
overflow-x: hidden;
align-items: center;
`;
const Row = styled.div`
width: 100vw;
display: flex;
align-items: flex-start;
justify-content: center;
transition: all 0.5s ease-in-out;
`;
<Wraapper>
<Row
key={index}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
ref={slideRef}
style={{
transform: `translateX(${x}vw)`,
}}
>
클릭하였을 때 인덱스를 증가하거나 줄이는 함수입니다.
여기서 setX를 +-56을 하였는데 x의 값을 변하게 하여 Row 에 있는 style을 통해 이미지가 옆으로 넘어가는 느낌을 주려고 했기 때문입니다. 그리고 저는 justify-content를 center에 두고 Row를 감싸는 Wrapper에는 overflow hidden을 주어서 5개의 이미지중 가운데인 3번째 이미지를 보이도록 하였습니다.
그래서 setX를 +- 56을 해주어서 이동하는 애니메이션 효과를 준 뒤 setTimeout을 이용하여 500ms 뒤에 다시 x를 0으로 돌려서 화면 스크롤을 가운데로 오도록 하였습니다.
2.드래그로 슬라이드 이동시키기
//드래그로 슬라이드 넘기기
const [isClick, setIsClick] = useState(false); // 드래그를 시작하는지 체크해줍니다.
const [mouseDownClientX, setMouseDownClientX] = useState(0); // 마우스를 클릭한 지점의 x 좌료를 저장합니다
const [mouseUpClientX, setMouseUpClientX] = useState(0); // 마우스를 땐 지점의 x 좌표를 저장합니다.
const onMouseDown = (event) => {
setIsClick(true);
setMouseDownClientX(event.pageX);
console.log(slideRef);
};
const onMouseLeave = (event) => {
setIsClick(false);
};
const onMouseUp = (event) => {
setIsClick(false);
const imgX = mouseDownClientX - mouseUpClientX;
// console.log(imgX);
if (imgX < -100) {
slideRef.current.style.transform = `translateX(${imgX}px)`;
increaseClick();
} else if (imgX > 100) {
slideRef.current.style.transform = `translateX(${imgX}px)`;
decreaseClick();
}
};
const onMouseMove = (event) => {
if (!isClick) return;
event.preventDefault();
setMouseUpClientX(event.pageX);
const imgX = mouseDownClientX - mouseUpClientX;
if (Math.abs(imgX) > 100) {
// slideRef.current.style.transform = `translateX(${imgX}px)`;
}
};
</LeftButton>
<Row
key={index}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
ref={slideRef}
style={{
transform: `translateX(${x}vw)`,
}}
>
제가 사용한 방법을 설명해드리자면 마우스를 클릭하였을 때 마우스가 클릭한 지점의 x 값을 저장하기 위해 mouse 이벤트 중 하나인 mouseDown을 이용하였고 마우스를 땐 지점의 x 값을 저장하기 위해 mouseLeave를 사용하였습니다.
그래서 두 값을 두 개의 변수에 따로 저장하여 두 값의 차이가 100 이상이라면 슬라이드를 넘기는 함수를 실행하도록 하였고 애니메이션 효과도 주어야 하기 때문에 useRef를 이용하여 Row에 ref={sliderRef} 를 해두어 Row의 style을 ref를 이용하여 효과를 주었습니다.
3.시간이 지나면 자동으로 슬라이드 하기
useEffect(() => {
const autoPage = setTimeout(() => {
setX(-56);
setIsSlide(true);
setTimeout(() => {
setIndex((prev) => (prev === 8 ? 0 : prev + 1));
setX(0);
setIsSlide(false);
}, 500);
}, 5000);
return () => {
clearTimeout(autoPage);
};
}, [index, isClick]);
useEffect 와 setTimeout 을 이용해 index,isClick 값이 변할때 실행되도록 하였습니다.
4. 반응형 사이트
const [windowWidth, setWindowWidth] = useState(window.innerWidth); // 사용자의 화면크기 정보를 받아 반응형 사이트에 사용합니다.
const resizeWidth = () => {
setWindowWidth(window.innerWidth);
};
useEffect(() => {
window.addEventListener("resize", resizeWidth);
return () => {
window.removeEventListener("resize", resizeWidth);
};
}, []);
화면 크기가 변함에 따라 css나 본문의 내용을 변경할 때 사용하기위한 변수를 만든 뒤 window.innerWidth 를 이용해 유저의 화면크기를 변수에 저장하고 useEffect에 window.addEventLister 을 사용하여 resize 될 때 이벤트에 반응하도록 하여 변수값을 변경해주었습니다.
좀더 자세한 코드는 깃허브에 가시면 보실 수 있습니다.
https://github.com/Gilpop8663/wanted_pre_onboarding
'react' 카테고리의 다른 글
Firebase 이란 ? Firebase 사용 방법 - 사용자 인증편(로그인,로그아웃,프로필 수정) (0) | 2022.02.20 |
---|---|
react-redux 설치 및 이용방법 (0) | 2022.02.11 |
React, 노마드 코더 강의 / 영화 사이트 만들면서 어려웠던 부분들 5가지 , 후기 (0) | 2021.12.24 |
React Query 에 대한 글 (0) | 2021.12.10 |
Recoil 에서 Selector 기능 get, set 사용법 (0) | 2021.12.04 |
- Total
- Today
- Yesterday
- env
- 프론트앤드
- NextRequest
- 우아한테크코스
- import/order
- CLASS
- javascript
- Storybook
- electron
- 스토리 북
- 위코드
- React
- 윤성우 열혈C프로그래밍
- createPortal
- 아차산
- nextjs
- 노개북
- error
- NextApiRequest
- 프리온보딩
- 초보
- C언어
- jest
- nodejs
- 북클럽
- TopLayer
- 원티드
- 노마드코더
- WSL2
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |