제 방을 소개합니다


프리뷰

프로젝트 소개


인테리어 서비스 플랫폼을 가정하고, 컴포넌트 내에서 가구 및 인테리어 용품 정보를 손 쉽게 확인할 수 있는 서비스를 개발해 보았다.

이번 포스팅에서는 해당 개인 프로젝트를 진행하며 발생했던 문제들과, 해당 문제들을 어떻게 해결했는지 정리해보려 한다.

배포 주소


https://house-deco.netlify.app/


🗂 z-index 제대로 짚고 넘어가기


툴팁 뱃지를 클릭했을 때 띄워지는 상품정보 박스가 툴팁뱃지에 가려지는 문제를 발견했다.
그래서 간단히 z-index를 줘서 해결해보려 했지만, 아무리 z-index를 건드려봐도 해결되지 않았다…

문제는 z-index값이 비교되는 방식에 있었다. 나는 단순히 상품정보 박스의 z-index가 높으면 높은대로 제일 상단에 위치할 것이라 생각했었다. 하지만, 나의 컴포넌트 구조는 툴팁 뱃지 아래에 자식으로써 상품정보 박스가 위치해 있었기 때문에, 문제가 발생했던 것이다.

그림으로 설명해보면 아래와 같다.

이렇게 상품정보 박스의 z-index만 높여주면 된다고 생각했던 것이다. 하지만 이 경우에는 아래의 그림과 같은 계산방식이 적용된다.

즉, 결국 상품정보 박스들은 툴팁뱃지의 자식들이기 때문에 아무리 z-index를 높여줘도 부모를 이길 수 없었던 것이다. 그리고 더 나아가, 부모(툴팁뱃지)들의 z-index는 모두 0으로 고정되어 있었기 때문에, 그 같은 z-index값으로 우열을 가릴 수 없으므로 HTML 태그가 배치된 index 순서에 따라 z-index값이 부여됐던 것이다.

해결 방법

간단히 해결했다.
상품정보 박스를 툴팁뱃지의 자식으로 배치하지 않고 형제 컴포넌트로 배치하니 문제가 해결됐기 때문이다.

그리고 각 상품정보 박스에 조건부 transform: translate(X, Y) 값을 줘서 박스들이 컨테이너 밖으로 돌출되지 않도록 하여 해당 작업을 마무리 했다.

코드

툴팁뱃지 코드

상품정보 박스 코드


🎨 Border에 Gradient 주기


처음 해보는 작업이라 조금 헤맸다.
그냥 단순하게 bordergradient값을 주려고 애썼지만, 생각해보니 background를 활용한 트릭을 쓰면 해결될 문제였다.

border에 gradient 넣기

  1. 부모 background 색의 디폴트 값에 원하는 색과 gradient값을 준다.
  2. 그리고 제품이 선택됐을 때 imgborder : 2px solid transparent 를 줘서 마치 border가 생긴것 과 같은 트릭을 준다.

코드

border gradient 코드 (60~65번 라인)


🖱️ Drag & Scroll


클릭했을 때 해당 제품의 위치로 translate을 하는 것은 그리 어렵지 않았지만, 드래그를 통해 제품 리스트를 스크롤되도록 구현하는 부분에서 조금 애를 먹었다.

처음에는 드래그값에 따라 움직여야 하는 distance값에 대한 state를 주고, 마우스 드래그 거리가 변할 때마다 해당 state를 업데이트해서 transform을 할까도 잠시 고민했었다. 하지만 그럴 경우 useRef를 쓰지 않는 이상 엄청나게 많은 리렌더링이 발생할 것 같아 바로 포기했다.

그러다가 scrollLeft값을 활용해서 이동을 시켜주면 어떨까 라는 생각이 들어 해당 방법을 적용해 보기로 했다.


내가 생각한 로직은 이하와 같다

  1. 우선, mouseDown이 아닐 때는 이동이 되지 않도록 isDown state를 생성

    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
    32
    const [isDown, setIsDown] = useState(false);

    export const ProductList = () => {
    // 1. isDown state 생성
    const [isDown, setIsDown] = useState(false);

    // 2. mouseDown이 됐을 때 setIsDown을 true로!
    const handleDown = (e: React.MouseEvent<HTMLElement>) => {
    e.preventDefault();
    setIsDown(true);
    };
    // 3. 손 떼면 isDown은 false
    const handleUp = () => {
    setIsDown(false);
    };
    // 4. 마우스가 움직였어도 isDown이 아니면 return!
    const handleMove = (e: React.MouseEvent<HTMLElement>) => {
    if (!isDown) return;
    e.preventDefault();
    };
    return (
    // 마우스 이벤트에 따라 호출될 함수들 선언
    <ListContainer
    onMouseLeave={handleUp}
    onMouseUp={handleUp}
    onMouseDown={(e) => handleDown(e)}
    onMouseMove={(e) => handleMove(e)}
    >
    <ListUl>...생략</ListUl>
    </ListContainer>
    );
    };

  1. mouseDown & mouseMove가 될 때 마우스 이동값을 구해 그 만큼 scroll되도록 구현

    1) 가장 먼저, 첫 클릭된 위치를 기록해야 한다. 이를 위해 startX라는 state를 만들어준다.

    1
    2
    const [isDown, setIsDown] = useState(false);
    const [startX, setStartX] = useState(0);

    2) 그리고 상대적 위치를 알아내기 위하여, useRef를 통해 DOM에 접근해 스크롤 박스 내에서의 이동값을 계산하기 위한 준비를 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const [isDown, setIsDown] = useState(false);
    const [startX, setStartX] = useState(0);
    const [scrollLeft, setScrollLeft] = useState(0);

    const containerRef: any = useRef();
    const handleDown = (e: React.MouseEvent<HTMLElement>) => {
    e.preventDefault();
    setIsDown(true);
    // 우리의 컴포넌트 컨테이너는 중앙에 정렬되어 있기 때문에 offsetLeft값을 빼줘야 스크롤 박스 내에서의 상대적 위치 계산이 가능하다
    setStartX(e.pageX - containerRef.current.offsetLeft);
    // 그리고 현재 스크롤된 만큼의 거리를 scrollLeft state에 업데이트 해준다.
    setScrollLeft(containerRef.current.scrollLeft);
    };

    3) 이제 마우스가 움직였을 때의 로직만 구현하면 된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const handleMove = (e: React.MouseEvent<HTMLElement>) => {
    if (!isDown) return;
    e.preventDefault();
    // mouseMoved에는 말 그대로 움직일 때마다의 마우스의 상대적 위치가 기록된다.
    const mouseMoved = e.pageX - containerRef.current.offsetLeft;
    // 그리고 toMove에는 위에서 저장된 마우스의 상대적 위치 - 처음 위치를 해주면 된다.
    const toMove = mouseMoved - startX;
    // 이제 스크롤박스 DOM의 scrollLeft 값을 업데이트 해주면 된다.
    containerRef.current.scrollLeft = scrollLeft - toMove;
    };

전체 코드

드래그 & 스크롤 구현 컴포넌트


Author

Hoonjoo

Posted on

2022-02-06

Updated on

2022-02-07

Licensed under

Comments