Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- component
- react-hook-form
- Gin
- storybook
- JPA
- go
- springboot
- RTK
- java
- frontend
- React
- Chakra
- JavaSpring
- satisfiles
- 웹애플리케이션서버
- ReactHooks
- typescript
- tanstackquery
- javascript
- test
- 오블완
- css
- hook
- 티스토리챌린지
- designpatterns
- Spring
- golang
- Redux
- backend
Archives
- Today
- Total
bkdragon's log
Carousel 본문
Carousel 은 슬라이드쇼를 말한다. 회전목마라는 뜻을 가지고 있다.
이벤트와 같은 것들을 광고하는 용도로 사용되는 것을 종종 볼 수 있다.
예시
- 커머스 (ex. 쿠팡)
- 상품의 사진을 Carousel을 통해 보여준다.
- Netflix
- 인기 작품, 추천 작품을 Carousel을 통해 보여준다.
장점
- 눈에 띈다. 주목하게 되는 효과가 있다.
- 효율적인 공간활용. 페이지를 넘기지 않고도 다양한 정보를 제공할 수 있다.
- 다양한 variation 이 있다. 자동으로 돌아가게 한다던지 다음 요소를 약간 노출한다던지, 버튼을 통해 다음 요소로 넘긴다던지 등이 있다.
단점
- 웹 접근성 문제가 생길 수 있다.
- 성능 저하. 웹 페이지 로딩 속도에 영향을 미칠 수 있다.
- 다양한 variation. 이는 단점이 될 수도 있다고 생각한다.
- 이미지의 크기나 비율로 인해 디자인 일관성 측면에도 문제가 생길 수 있다.
구현
버튼을 통해 이전과 다음 요소를 의도적으로 볼 수 있고 dot 요소를 통해 현재 이미지가 몇번째인지 확인 가능하고 auto는 설정을 통해 적용할 수도 적용하지 않을 수도 있게 구현해보려고 한다.
Carousel.tsx
import React, { useState, useEffect, useCallback } from 'react';
import styles from './carousel.module.scss';
import classNames from 'classnames/bind';
const cn = classNames.bind(styles);
interface Props {
images: string[];
interval?: number;
}
const Carousel: React.FC<Props> = ({ images, interval }) => {
const [current, setCurrent] = useState<number>(0);
const next = useCallback(() => {
if (current < images.length - 1) {
setCurrent((prev) => prev + 1);
} else {
setCurrent(0);
}
}, [images.length, current]);
const prev = useCallback(() => {
if (current === 0) {
setCurrent(images.length - 1);
} else {
setCurrent((prev) => prev - 1);
}
}, [images.length, current]);
const clickDot = (index: number) => {
setCurrent(index);
};
useEffect(() => {
if (!interval) return;
const timer = setInterval(next, interval);
return () => {
clearInterval(timer);
};
}, [interval, next]);
return (
<div className={cn('container')}>
{images.map((item, index) => (
<img
src={item}
key={index}
className={cn('item')}
style={{ transform: `translateX(${current * -800}px)` }}
alt="a"
/>
))}
<button className={cn('button')} onClick={prev}>
{'<'}
</button>
<button className={cn('button', 'button_right')} onClick={next}>
{'>'}
</button>
<div className={cn('dot_wrapper')}>
{images.map((_, index) => (
<div
key={index}
className={cn('dot', { dot_active: current === index })}
onClick={() => clickDot(index)}
/>
))}
</div>
</div>
);
};
export default Carousel;
- Carousel에서 보여줄 이미지의 리스트는 부모로부터 받아오고 있다.
- interval 값이 있으면 auto로 움직인다. useEffect를 통해서 현재 index 값을 지속적으로 증가시켜주는 식으로 구현했다.
- 현재 index 값에 따라 보여지는 이미지가 결정된다. 각 이미지는 Container(부모 div)를 가득채우는 크기이고 현재 index 값에 따라 translate 값이 변경되어 이미지가 움직인다.
- 각 이미지에는 flex : 0 0 100% 가 적용되어 있는데 flex-shrink 가 0가 임으로 container와 관계없이 고정 폭이 된다.
상태를 사용하니 이미지 이동을 간단하게 구현할 수 있었다. 다만 아쉬운 점은 인라인 스타일을 통해 translate를 변경해주고 있는 부분인데 scss를 사용하니 상태와 엮어서 할 수 있는 방법이 저것 말곤 없었다(일단은). styled-components를 사용하면 좀 더 선언적으로 구현이 가능하긴하다.
잘생기고 멋진 공유님 이미지로 사용해보았다!
'UI UX' 카테고리의 다른 글
flex : 1, overflow : auto issue ! (1) | 2024.07.24 |
---|---|
Button (with Chakra) (0) | 2023.08.25 |
제출 폼 (0) | 2023.08.23 |
드롭 다운 메뉴 (0) | 2023.08.21 |
아코디언 메뉴 (0) | 2023.08.13 |