개발새발 로그

[2024-01-25] 개인 프로젝트 회고 본문

TIL

[2024-01-25] 개인 프로젝트 회고

이즈흐 2024. 1. 25. 03:27

일단은 오늘 만들면서 생긴 문제점들을 적어보려고한다.

 

 

1. e.nativeEvent는 뭐야?

나는 MouseMove 이벤트에서 event 값을 이용해 현재 요소를 기준으로 마우스 좌표를 가져오려고 했다.

왜냐하면 그 마우스 좌표에 따라 카드가 기울어져야했기 때문이다.

 

근데 offsetX를 쓰려고 하니까 event.offsetX가 안됐다.

그래서 찾아보니 nativeEvent를 중간에 사용해야 한다고 나와있었다.

 

nativeEvent가 뭐야..?

nativeEvent는 브라우저에서 제공하는 원시 이벤트 객체에 직접 접근하기 위한 도구

 

왜 리액트에는 nativeEvent가 있는거야?

React에서 이벤트 핸들러는 브라우저에서 직접 발생한 원시(native) 이벤트가 아닌,

React가 생성한 SyntheticEvent를 받는다고 한다.

 

SyntheticEvent는  브라우저 간의 일관성을 유지하면서

React에서 이벤트를 처리하기 위해 만들어진 가상의 이벤트 객체라고 한다.

 

브라우저 간의 일관성을 유지하면서 이벤트를 처리해야하는 이유?

웹 브라우저는 웹 페이지에서 발생한 이벤트에 대한 정보를 포함하는 이벤트 객체를 생성한다.

이 객체에는 이벤트의 유형, 대상 요소, 마우스 위치 등과 같은 다양한 정보가 포함되어 있다.

그러나 브라우저마다 이 이벤트 객체의 구조와 속성이 조금씩 다를 수 있다.

 

 

브라우저의 일관성이 왜 필요해?

사용자가 어떤 브라우저를 사용하든지 동일한 웹 경험을 제공하고,

코드를 작성하는 개발자는 가능한 한 많은 브라우저에서 일돤되게 동작하는 코드를 작성하려고 노력한다.

React와 같은 라이브러리는 이러한 브라우저 간의 차이를 처리하고

개발자가 일관된 코드를 작성할 수 있도록 도와줍니다.

React의 SyntheticEvent는 이러한 일관성을 유지하기 위한 방안 중 하나다.

 

즉, React의 SyntheticEvent는 브라우저 간의 이벤트 핸들링을 일관되게 만들기 위해 만들어진 것이다.

이벤트가 발생하면 React는 해당 이벤트에 대한 SyntheticEvent를 생성하고,

모든 브라우저에서 동일하게 동작하도록 보장한다.

 

 

2. rotate를 위한 공식..?

일단 내가 필요한 값이 아래와 같았다.

마우스 x좌표가 +200이면 rotateY(-20deg)이어야한다.

마우스 x좌표가 0이면 rotateY(20deg)이어야한다.

이게 왜 그러냐면 그림으로 알려주겠다.

마우스가 왼쪽으로가면 오른쪽으로 점점 기울어야하고,

마우스가 오른쪽으로가면 왼쪽으로 점점 기울어야한다.

즉 마우스가 오른쪽에 있으면 아래와 같다.

그럼 trasform : rotateY(??deg)에서 물음표에 어떤 동적인 값을 넣어야하는 것일까?

간단한 방정식으로 가능하다.

 

마우스 x좌표가 +200이면 rotateY(-20deg)

마우스 x좌표가 0이면 rotateY(20deg)

->

필요한 rotatetY는  일차함수로 ax+b로 표현하자

->

두개의 점을 지난다

(200,-20)

(0,20)

->

이걸 위 규칙으로 대입하면

-20 = 200a+b

20 = 0a+b

-> 이걸 계산하면

[ -20 = 200a + b ] [ 20 = 0a + b ]

두 번째 방정식에서 바로 (b = 20)임을 알 수 있다.

이제 (b)의 값을 알았으니, 첫 번째 방정식에 (b = 20)을 대입해서 (a)의 값을 구할 수 있다.

[ -20 = 200a + 20 ]

이제 이 방정식을 (a)에 대해 풀면 된다

[ -20 - 20 = 200a ]

[ -40 = 200a ]

[ -1/5 = a ]

따라서, ( a = -1/5 ), (b = 20) 이다.

 

 

그럼 아래 조건도 가능하다.

마우스 Y좌표가 +300일 때, rotateX는 -20

마우스 Y좌표가 0일 때, rotateX는 20

->

(300,-20)

(0,20)

->

-20 = 300a + b

20 = 0a+b

-> 

바로 계산해서 (a = 2/15) (b = 20) 이다.

 

 

3. 뒤에는 RGB그림자, 앞에는 조명 효과.. 아이구 복잡해~

뒤에는 RGB그림자..

앞에는 마우스가 움직일때마다 조명효과를 줘야했다.

이전에 MouseMove를 사용했어서 조명효과는 쉬웠다.

 

하지만 이 둘을 합쳐야할 때 조금 복잡하게 생각했다.

<div> 요소를 3개를 써야 하나? 라는 생각도 했는데

일단 나는 before과 after을 사용해서 해결했다.

const CardContainer = styled.li<CardContainerProps>`
  border-radius: 18px;
  display: flex;
  flex-direction: column;
  position: relative;
  transition: all 0.1s ease;
  transform-style: preserve-3d;
  transform: perspective(350px) rotateX(${props => props.tiltX}deg)
    rotateY(${props => props.tiltY}deg);
  will-change: transform;

  &::before {
    ...
  }
  &::after {
    ...
  }
`

근데 이렇게 하다보니 하나의 요소에 너무 많은 일을 하는 것 아닌가? 싶었다.

그래서 div요소를 나눠서 하려고 하니까 transform의 3D효과 때문인지 z-index도 먹히지 않아서,

자꾸 조명효과 div가 뒤로가게 됐다.

그리고 기울면 같이 기울어야하는데 같이 기울지도않았다.

이게 같이 transform rotate를 해줘야해서 그런건가? 싶었다,

사실 이 부분은 왜 그런건지 아직 파악하지 못했다.

 

보통은 class를 추가해서 before을 넣고 그렇게 해서 여기에 대해  예상을 하지 못했다.

 

4. z-index랑 transform: translateZ(-1px) 둘이 다른게 뭔데?!

내가 z-index를 써서 RGB그림자를 뒤에 넣으려고 했는데 계속 컴포넌트 앞에서 출력되고 있었다.

그래서 before과 after때문인가 싶어서 앞에 조명이랑 뒤에 RGB그림자랑 바꿔줬는데도 안됐다.

transform-style: preserve-3d;

그래서 이 속성 때문인가? 했다.

이 속성은 부모-자식 요소 간의 3D 공간을 일치시키고자 할 때 사용한다.

아래와 같은 상황이면

.parent {
  transform-style: preserve-3d;
}

.child {
  transform: translateZ(50px);
}

.parenttransform-style: preserve-3d;를 적용하면

.child translateZ(50px).parent의 3D 공간에 영향을 미치게 된다.

이렇게 함으로써 부모와 자식 간의 일관된 3D 공간이 유지된다.

 

근데 이 속성이 없으면 before에서 RGB조명이 컴포넌트를 아예 덮어씌워서 출력됐다.

왜 그런가 보니 before에서 아래 속성을 지정하고 있었다.

transform: translateZ(-1px);

이게 3D효과라서 둘 중 하나의 속성만 없어도 RGB조명이 덮어 씌우게 됐다.

그래서 그냥 이걸 지우고 모든 요소에 z-index를 넣어줬다.

 

이유는

3D 변환은 그 자체로 성능이 좋을 수 있지만,

모든 요소에 대해 transform-style: preserve-3d;를 사용하면 성능에 영향을 주기도 하고,

일부 구형 브라우저에서는 3D 변환 및 transform-style: preserve-3d;를 완전히 지원하지 않을 수 있어서 제외했다.

 

4. 나 애니메이션 할래..(고치는 중..)

const rotateAndScaleIn = ({
  currentX,
  currentY
}: {
  currentX: string
  currentY: string
}) => keyframes`
  0% {
    transform: perspective(350px) rotateX(0deg) rotateY(0deg) scale(1) translateX(0) translateY(0);
  }
  100% {
    transform: perspective(350px) rotateX(0deg) rotateY(360deg) scale(1.2) translate(${currentX}, ${currentY})
  }
  
`

const rotateAndScaleOut = ({
  currentX,
  currentY
}: {
  currentX: string
  currentY: string
}) => keyframes`
  0% {
    transform: perspective(350px) rotateX(0deg) rotateY(360deg) scale(1.2) translate(${currentX}, ${currentY})
  }
  100% {
    transform: perspective(350px) rotateX(0deg) rotateY(0deg) scale(1) translateX(0) translateY(0);
  }
  
`

animation: ${props =>
      props.isClicked ? rotateAndScaleIn : rotateAndScaleOut}
    2s forwards;
...


  const [isClicked, setIsClicked] = useState(false)
  
   const handleCardClick = () => {
    setIsClicked(!isClicked)
  }

이런 식으로 currentX와 currentY에는 

(현재 요소의 좌표값- 뷰포트 중앙 좌표값)을 넣어줘서 클릭하면 애니메이션이 진행하도록 했다.

그래서 useRef도 써서 현재 요소 좌표값도 가져오고

window.clinetX도 써서 정중앙 좌표값도 가져왔다.

근데 애니메이션을 적용하고 실행되면 기울기 하던 transform이 기능을 못하는 것이다!

 

그래서 이 문제는 계속 고쳐봐야한다..!

 

배운 것 

1. 나 linear-gradient를 조금 배웠다..!

 background: linear-gradient(
      120deg,
      transparent 10%,
      rgba(255, 219, 112, 0.4) 20%,
      rgba(132, 50, 255, 0.4) 25%,
      transparent 60%,
      rgba(255, 219, 112, 0.4) 68%,
      rgba(132, 50, 255, 0.4) 76%,
      transparent 100%
    );

 

요건 카드 앞의 빛나는 조명 효과인데

설명하자면

120각도로

10%까지는 투명하게

그 이후 10%는 rgba값

그 이후 15%는 rgba값 ... 

요런식으로 진행하는 것이었다!

 background: linear-gradient(#fff0 0%, #fff0 70%, #1d1d1d 100%)

요것도 똑같다.

 0%에서 #fff0 색상이 시작하고,

70% 지점에서 계속해서 #fff0이며,

그 이후에는 100%에서 #1d1d1d로 변화하는 선형 그라디언트를 생성하는 것이다!

 

 

728x90
반응형
LIST