Vue 기능을 활용한 Transition 적용기

화면 요소에 움직임을 표현해야 할 때, css보단 script나 javascript framework에서 제공하는 기능을 이용하여 쉽고 간편하게 Transition을 적용하는 방법을 공유합니다.

작성일 2023년 03월 29일

안녕하세요, IMQA 프론트엔드 주니어 개발자 권경민입니다.

Javascript와 Java를 주로 이용하여 개발하다 보니 퍼블리싱에 익숙하지 않아, 화면 요소에 움직임을 표현해야 할 때, CSS보단 Javascript나 Javascript Framework에서 제공하는 기능을 이용하여 쉽고 간편하게 Transition을 적용하려고 했습니다.

그래서 오늘은 저처럼 퍼블리싱과 CSS가 익숙하지 않은 프론트엔드 개발자분들에게 Vue Transition을 적용한 경험에 대해 이야기 해보려고 합니다.

Transition?

홈페이지를 돌아다니다 보면 메뉴바 등 화면 요소가 움직이는 것을 경험하신 적이 있으실 텐데요.

화면 요소가 변화한다는게 느껴지네요.

개발자 도구로 스타일을 확인해 볼까요?

transition이라는 css 속성이 있는데요. 해당 속성을 지우면 어떻게 될까요?

도형이 바뀌는게 느껴지긴 한데.. 뭔가..

조금 밋밋하게 바뀌었네요. 확실히 transition 속성이 있는 게 도형이 바뀐다는 느낌이 확 느껴집니다.

홈페이지에 Transition를 찾아보니 이런 문구가 있습니다.

Transitions enable you to define the transition between two states of an element.
(Transition은 하나의 element의 2가지 상태간 변화를 정의해줄 수 있다.)

다시 말하면 Transition은 CSS를 이용해 요소의 변화에 애니메이션을 적용할 수 있는 기능입니다.

요소의 상태 간의 변화를 정의하는 속성
/* transition 사용법 */

/* 변화할 요소 | 변화 시간 | 변화 속도 | 딜레이
/* property name | duration | easing function | delay */
transition: margin-right 4s ease-in-out 1s;

transition: all 0.8s ease;
  • property: 애니메이션을 적용할 CSS 속성을 지정합니다. (ex: background-color, width, height 등)
  • duration: 애니메이션의 지속시간을 지정합니다. (ex: 0.5s, 1s 등)
  • timing-function: 애니메이션의 타이밍 함수를 지정합니다. (ex: ease, ease-in-out, linear 등)
  • delay: 애니메이션의 지연시간을 지정합니다. (ex: 0.2s, 1s 등)

그래서 Vue Transition은 뭐가 다른가요?

그전에 왜 Vue만의 Transition을 사용하게 됐는지 알아야겠죠!

기능 요구 사항

[목록 추가] 버튼을 누르면 사용자 정보를 [입력하는 영역]이 나타나는 기능이 있습니다.

클릭 시 버튼의 테두리 영역이 늘어나면서 [목록 추가]라는 텍스트는 보이지 않고 사용자 정보를 입력하는 input이 나타나야 합니다.

Vue의 element 관리 방법

Vue에서 특정한 조건이 되면 element를 노출시키고 감추는  v-if/v-show 기능이 있습니다. v-if/v-show의 조건이 참이 되면 element가 등장하고, 조건이 거짓이 되면 element가 퇴장합니다.

https://vuejs.org/api/built-in-directives.html

이러한 기능을 우리의 요구사항에 적용해 본다면 “목록 추가하기” 버튼을 눌렀냐/안 눌렀냐로 flag를 만들 수 있고, 그에 따라 v-if/v-else로 버튼이 나오게 혹은 게스트 정보를 입력하는 input들이 나오게 하면 되겠네요?

<div class="tester-create" @click="isShow = !isShow">
  <button v-if="isShow">목록 추가</button>

  <div v-else class="tester-detail__guest-card">
    <p>목록 추가</p>
    <tester-input :placeholder="'이메일을 입력하세요'" label="이메일" />
    <tester-input :placeholder="'이름을 입력하세요'" label="이름" />
    <tester-input :placeholder="'비밀번호을 입력하세요'" label="비밀번호" />
  </div>
</div>

여기서 문제!
다른 엘리먼트에 transition을 적용할 수 있을까요?

다른 엘리먼트에 transition을?

Transitions enable you to define the transition between two states of an element.
(Transition은 하나의 element의 2가지 상태간 변화를 정의해줄 수 있다.)

라고 했는데, button과 input, element가 다른데 transition이 적용되나요? (안 됩니다)

요소가 생성되거나 삭제될 때, 애니메이션 효과를 적용할 수 없습니다.

우리의 상황이 딱 요소가 등장하고 퇴장하는 상황인데 이러한 상황에선 CSS Transition이 적용되지 않는다고 하네요.

그래서 현재 상황과 같이 element의 등장과 퇴장에 transition을 줄 수 있는 Vue 기능을 찾았습니다.

Transition | Vue.js
Vue.js - The Progressive JavaScript Framework
Transition 설명 중

It can be used to apply enter and leave animations on elements
- 엘리먼트들의 enter와 leave에 애니메이션을 줄때 사용할 수 있다.

The enter or leave can be triggered by one of the following [v-if, v-show…]
- enter와 leave는 v-if, v-show 로 발생시킬 수 있다.

Vue Transition은 Vue에서 제공하는 기능으로, element가 등장하거나 퇴장할 때 애니메이션을 적용할 수 있습니다.

https://vuejs.org/guide/built-ins/transition.html#the-transition-component
  • enter: v-if/v-show의 조건에 따라 element가 나타날 때
  • leave: v-if/v-show의 조건에 따라 element가 사라질 때

각각의 상황에서 해당 클래스가 붙습니다.

  • v-enter: 요소가 나타나기 시작할 때 적용
  • v-enter-active: 요소가 나타나는 트랜지션이 진행되는 동안 적용
  • v-enter-to: 요소가 나타나는 트랜지션이 완료될 때 적용
  • v-leave: 요소가 사라지기 시작할 때 적용
  • v-leave-active: 요소가 사라지는 트랜지션이 진행되는 동안 적용
  • v-leave-to: 요소가 사라지는 트랜지션이 완료될 때 적용

적용하기

기능 요구사항

* Keypoint
1. 테두리 영역이 늘어나야 한다.
 → button과 input div를 감싸는 div에 transition
2. Vue Transition을 이용해 등장/퇴장에 opacity(투명도) 조정하여 자연스럽게 등장

<div class="tester-create active" @click="expanded = !expanded" 
	:class="{active: expanded}">
  <Transition name="display">
    <button v-if="elementToggle">
      <span class="tester-create__icon"><img src="/assets/img/plus_icon.svg" :alt="'목록 추가'"></span>
      <span class="tester-create__text">목록 추가</span>
    </button>
    <div v-if="!elementToggle" class="tester-detail__guest-card">
      <p>목록 추가</p>
      <tester-input :placeholder="'이메일을 입력하세요'" label="이메일" />
      <tester-input :placeholder="'이름을 입력하세요'" label="이름" />
      <tester-input :placeholder="'비밀번호을 입력하세요'" label="비밀번호" />
      <base-button-group/>
    </div>
  </Transition>
</div>
// expanded 값이 바뀔때 동작하는 함수

watch: {
  expanded() {
    this.elementToggle = !this.elementToggle
  }
},
.tester-create {
  background-color: #ffffff;
  border: 1px solid #7B6FCC;
  border-radius: 10px;
  height: 60px; // 기본 높이
  align-items: center;
  margin-bottom: 6px;
  overflow: hidden;
  transition: all 0.3s ease; // 0.3초 동안 높이 변화
  padding-top: 12px;

  &.active{
    display: flex;
    align-items: center;
    padding-top: 0;
    height: 370px; // 변화된 높이
    width: 100%;
  }
}

.display-enter-active,
.display-leave-active {
  transition: opacity 0.3s ease; // 0.3초 동안 투명도 변화
}

.display-enter-from,
.display-leave-to {
  opacity: 0; // 등장하기 시작, 퇴장의 마지막은 투명도 0
}

1차 결과

opacity가 변화하는 동안 기존의 element가 퇴장하지 않고 새로운 element가 등장하여 영역이 겹칩니다.

Vue Transition의 mode 속성

Vue Transition은 mode 속성을 사용하여 등장과 퇴장 시점에 애니메이션을 적용하는 방식을 조절할 수 있습니다. mode 속성의 값으로는 in-outout-in을 사용할 수 있습니다.

  • in-out: 등장하는 element의 애니메이션이 끝나기 전에 퇴장하는 element의 애니메이션을 적용합니다.
  • out-in: 퇴장하는 element의 애니메이션이 끝나면 등장하는 element의 애니메이션을 적용합니다. mode 속성의 기본값은 in-out입니다.

기존의 element가 완전히 퇴장한 후에 새로운 element가 등장하도록 mode=”out-in” 속성을 추가합니다.

<div class="tester-create" @click="expanded = !expanded" 
	:class="{active: expanded}">
  <Transition name="display" mode="out-in"> // ** mode 추가 **
    <button v-if="elementToggle">
      <span class="tester-create__icon"><img src="/assets/img/plus_icon.svg" :alt="'목록 추가'"></span>
      <span class="tester-create__text">목록 추가</span>
    </button>
    <div v-if="!elementToggle" class="tester-detail__guest-card">
      <p>목록 추가</p>
      <tester-input :placeholder="'이메일을 입력하세요'" label="이메일" />
      <tester-input :placeholder="'이름을 입력하세요'" label="이름" />
      <tester-input :placeholder="'비밀번호을 입력하세요'" label="비밀번호" />
      <base-button-group/>
    </div>
  </Transition>
</div>

2차 결과 (최종)

마무리

드디어 Vue Transition을 이용하여 요구사항처럼 완성했습니다!

사실 제 사수분이 publishing 고수신데요. (눈감고도 마크업 하십니다.) 제가 Vue transition까지 사용해가면 끙끙거리는 모습을 보시고 css transition만으로도 할 수 있을 것 같다고 하시긴 했는데… 저는 아무리 해도 안 되더라구요.

아무튼 사용해보지 못한 Vue의 기능을 사용해본 경험은 재밌었습니다. 결과물도 요구사항대로 나왔으니 만족합니다.

저처럼 다른 Element 간 transition을 자연스럽게 적용해야 하는 상황에 처하신 프론트엔드 개발자분들 혹은 퍼블리셔분들에게 이번 포스팅이 도움이 됐으면 합니다.

감사합니다.

Share on

Tags

IMQA 뉴스레터 구독하기

국내외 다양한 기술 소식을 선별하여 매월 전달해드립니다. IMQA 뉴스레터를 통해 기술 이야기를 함께해보세요.

구독하기