본문 바로가기
React

React(48) 타입스크립트 - 토글 메뉴에 animation 효과주기

by 새발개발JA 2021. 9. 14.
반응형

타입스크립트와 리액트로 메뉴 접고 펼치기 기능을 구현 중이다.

토글까지는 아주 쉽게 구현을 하였지만, 자연스럽게 펼쳐지는 애니메이션을 적용하려니 아~주 골치가 아팠다. ㅠㅠ 

 

동적인 코드에 애니메이션 기능은 처음이라 한참 헤매였다. 하지만 언제나 그렇듯, 항상 어렵사리 해결을 하면 몇줄의 코드로 끝나게 된다. 조금 허무하기도 하지만 뿌듯하다.

자 그럼 이제 만들어보자.

 

이슈

- @key frame 을 적용한 animation 속성을 이용하려 하였으나 양방향 애니메이션이 적용이 되지 않았다.
- 토글 기능을 적용한 메뉴는 동적으로 받아온 api 객체를 사용하여 보여준다. 즉 동적으로 height 속성을 적용하려니 동작이 되지않았다. ex) 이런식으로 height : calc(100% - 20px)

 


React(48) 타입스크립트 - 토글 메뉴에 CSS Animation 효과주기

 

결과화면 미리보기

 

- 메뉴를 열었을 때

동적으로 가져온 리스트들만큼 height 가 동적으로 늘어나며 자연스러운 애니메이션으로 촤라락 내려온다.

 

- 메뉴를 접었을 때

Height 이 없어지며 리스트가 사라지며 버튼 방향이 바뀐다. 자연스러운 애니메이션으로 촤라락 올라온다.

 

List.tsx

화살표 버튼을 클릭하면, class 이름이 변경되면서 화살표 아이콘의 방향이 바뀌고

동시에 onClick 함수가 실행된다. 함수 내에서는 closeList 라는 상태변수의 값에 따라 closeList 가 true 이면 메뉴가 접히고, false 이면 보여지게 만든다.

import { ReactElement, useState, useRef } from 'react';
import arrow from '/img/arrow-icon.png';
import '/css/List.scoped.css';

const List = (): ReactElement => {
  const [closeList, setCloseList] = useState<boolean>(false); // 얘가 열고접는 스위치역할이 된다.
  const listRef = useRef<HTMLDivElement>(null); 	      // useRef 로 특정 DOM 에 접근할 거다.
  
  // 클릭시 실행되는 함수
  function foldList() {
    if (!listRef || !listRef.current) {	// useRef 변수가 비었을 때
      return;				// 그냥 리턴하도록 예외처리를 해주자
    }
    
    const style = listRef.current.style;  // 접근할 DOM 요소의 스타일 속성을 미리 선언해둔다.
 
    if (closeList) {			  // closeAllList 상태변수가 true 일 때 
      style.maxHeight = '0'; 	  	  // maxHeight 는 0이 되고 접힌다.
    } else if (!closeList) {	  	  // closeAllList 상태변수가 false 면 
      style.maxHeight = 		
      	`${listRef.current.scrollHeight}px`; // maxHeight = scroll 길이가 되고 메뉴가 열린다.
    }
    setCloseList(!closeList);		  // 클릭할 때마다 상태를 반대로 바꾼다.
  }
  
  return (
    <div>메뉴리스트</div>
      <button
         className={`${closeList ? 'close' : 'open'}`}  // 상태값에 따라 class이름이 바뀐다.
         onClick={foldList}				// 클릭하면 foldList() 함수가 실행된다. 
      >
        <img src={arrow} />
      </button>
    </div>
    <div className="content" ref={listRef}> // ref로 지정해주면 직접 이 요소에 접근한다.
      {list}				    // 동적으로 받아오는 리스트이다. (받아오는 과정은 생략)
    </div>
  );
};
export default List;

 

List.css

여기서 css의 역할은 크게 두가지이다.

화살표 아이콘을 열고 접는 것과 애니메이션 속성을 설정 해주는 것이다. 

.open img {  
  transform: rotate(180deg); // 화살표 아이콘 방향돌리기 
}

.content {
  overflow: hidden;
  transition: max-height 0.3s ease-out; // 애니메이션 속성 설정해주기
}

 

** transition 에서 max-height 을 사용할 경우 auto 같이 responsive 한 상대 값은 적용이 되지 않는다.

그래서 예제 코드의 경우 max-height 을 동적으로 감지하여 주입하는 로직을 사용하였다.

 

** transitive 은 동적인 사이즈의 변화가 일어나는 <div 태그> level 에서 사용해준다.

 

 

반응형

댓글