Programming/Lib, Frameworks

[Vue.js] 뷰 트랜지션(transition)의 사용 방법과 치명적인 문제점

WANJIN 2018. 9. 22. 22:45
반응형

 

 

뷰 최신 버전인 2.5.17 버전에서 트랜지션을 사용해보았다.

 

참고로 그 사용 방법은 Vue.js 공식 페이지에 기가막히게 잘 나와있다.

 

 

 

뷰 트랜지션을 써보다가 마주친 문제를 설명하기에 앞서, 그놈을 어떤식으로 사용하는지 알아보자아~.

 

 

 

뷰(Vue) 트랜지션 사용하기

 

뷰 트랜지션을 이용하여, 로고 3개를 차례로 뿅뿅뿅 나타나게하는 효과를 적용해보려고 한다.
 

 

 

뷰 템플릿(template) 작성

  <transition-group name="fade" v-on:after-enter="fadeNext" tag="div" class="text-center">      <img v-show="fade[0]" key="0" class="logo" src="../assets/logo.png">      <img v-show="fade[1]" key="1" class="logo" src="../assets/logo.png">      <img v-show="fade[2]" key="2" class="logo" src="../assets/logo.png"> </transition-group>    

 

 

먼저 template 부분인데, 아주아주 간단하다.

 

  1. 그냥 "transition-group" 이라는 태그를 사용해주면 되고, 

  2. 효과 이름을 정해서 name="내가 정한 트랜지션 이름" 의 형태로 속성을 넣어주고,
  3. 자식 엘리먼트들에다가 'key'를 부여해주자.

  4. 그리고, 이 효과가 나타나게 해주는 switch 역할을 하는 v-show="내가 정한 switch 데이터 변수명" 을 추가해준다(요놈 스위치 변수는 아래 script 코드 부분에서 추가할거심).
  5. 마지막으로, 우리는 세 개의 로고가 뿅뿅뿅 차례차례 뜨도록 하는게 목적이니까, 첫번째 로고가 다 뜨면 다음 로고가 뜨도록 하는 메소드를 호출해주어야 한다. 
    요거슨 뷰에서 트랜지션 훅(hook)을 제공해주니, 그것을 이용하면 된다. 
    사용하는 방법은 다양한데, 나는 'v-on' 디렉티브를 이용하는 방법을 선택했다.
    v-on:after-enter="내가 정한 메소드명" 형태로 집어넣어 주면 된다(훅 메소드도 아래 script 코드 부분에서 가할 것이니 인내하자).

 

 



<참고>


트랜지션 훅(hook) 메소드는 총 8가지가 있다.


v-on:before-enter
v-on:enter
v-on:after-enter
v-on:enter-cancelled

v-on:before-leave
v-on:leave
v-on:after-leave
v-on:leave-cancelled



각각이 어떤 것인지는 뷰 가이드에 두말하면 입아프게 너무나도 자세히 나와 있으니, 


조오기 위에 링크 눌러서 참고하시길.

 

 

 

 

 

아직까지는 아무런 효과를 적용해주지 않았으므로 걍 아래와 같은 정적인 상태가 보일 거심.

 

 

 

 

 

 

 

뷰 스타일(style) 코드 작성

얘가 뿅뿅 나타나도록 CSS 코드로 Fade-in 효과를 만들어보자.

 

   .fade-enter {   opacity: 0; } .fade-enter-active {   transition: opacity .5s; };   

 

이 코드는, "fade" 라는 이름의 뷰 트랜지션을 정의해준다.

 

트랜지션 진입 시 처음 상태"fade-enter"로 정해주고,

트랜지션 효과"fade-enter-active"로 정해준다.

 

위 코드를 통해 "fade"라는 뷰 트랜지션은

=> 처음에는  'opacity: 0' 에서 시작해서 0.5초동안 opacity가 1로 변하는 트랜지션

이라고 이해하면 된다.

 

 

 

뷰 스크립트(script) 코드 작성

이제 중요한 것 2가지가 남았다.

 

1. 처음에 트랜지션 효과가 일어나도록 해주는 스위치를 만들어주는 것과,

 

2. 첫번째 엘리먼트에 트랜지션 효과가 끝났으면, 그 다음 엘리먼트에 효과가 일어나도록 하는 훅 메소드를 만들어주는 것.

 

  let fadeIdx = 0  export default {   ...   data() {     return {       fade: [false, false, false]     }   },   methods: {     fadeNext: function() {        this.fade.splice(fadeIdx++, 1, true)     }   },   mounted() {     setTimeout(this.fadeNext, 1000)   } } ...   

 

fade 배열은 각각의 로고 이미지들의 트랜지션을 시작시켜주는 스위치들의 배열이다.

 

default 값이 모두 false 이므로, 어디선가 누군가가 값을 true로 바꿔주지 않으면, 트랜지션 효과는 일어나지 않는다.

 

 

fadeNext 함수다음 순서의 트랜지션 스위치를 켜는 역할을 한다.

 

즉, fade 배열에서, 다음 인덱스의 스위치를 켜는 역할을 한다.

 

인덱스 값의 default가 0이므로, 맨 처음 트랜지션도 해당 함수로 켜면 된다.

 

(위 코드에서는 mount가 되면, 1초 뒤에 맨 처음 로고의 트랜지션이 시작되도록 해놔씀)

 

 

 

 

결과물, 그리고...

 
 

 

 

 

 

읭...?

 

뭔가 이상하지 않음?

 

원하던 아름다운 그림이 아닐 거시다.

 

'by WANZARGEN' 이 위에있다가, 로고 트랜지션이 시작되어야 제자리로 내려간다...

 

by WANZARGEN 요거슬 괜히, 그냥, 한 번 짱인 척 할라고 넣은 것이 결코 아녀. 

 

 

그 뿐만이 아님.

 

얘네들이 제자리에서 뿅뿅뿅 하고 뜨는게 아니라, 하나가 생길때마다 왼쪽으로 밀려난다는...

 

 

 

 

문제점

 

이러한 현상이 나타나는 이유는 아주 심플하다.

 

뷰의 트랜지션은 기본적으로 v-if, v-show 를 사용하여 트랜지션을 시작시키도록 되어있다.

 

 

뭔말이냐,

 

아까 위에서 '트랜지션 스위치' 역할을 하는 변수가 있다고 했잖음?

 

그 친구가 true면  v-if = true  혹은  v-show = true  가 되고, 해당 엘리먼트가 화면에 보여지기 시작한다는 말이 된다.

 

 

이렇게 엘리먼트가 화면에 출력되는 때가 트랜지션이 시작되는 때라고 이해하면 된다.

 

 

 

요까지만 말해도 이해하는 당신, 아래 '참고2'는 제끼십쇼.

 

 

 



<참고2>


    • v-if

      이 친구는 그 대응 값이 false이면 DOM 트리에 아예 렌더링 자체가 안된다.


    • v-show

      이 친구는 그 대응 값이 false이면 렌더링은 되지만, 출력이 안된다.

      그 출력이 안되는 방식이 중요한데, 해당 엘리먼트의 스타일을 "display: none" 처리 해버린다.

      "display: none" 처리를 하게 되면, 해당 엘리먼트가 차지하는 영역 또한 사라지게 된다.

      해당 영역을 살리고 싶으면,  "visibility" 속성을 이용하면 된다.

      "visibility" 속성을 'hidden' 으로 설정하면 엘리먼트가 차지하는 영역은 살리되, 안보이게 할 수 있다.

      또 다른 방법으로는, "opacity" 속성 값을 0으로 두어 투명하게 하는 방법이 있다.

 

 

자신의 영역이 없다가, 트랜지션 스위치가 켜지는 때에 영역이 생겨버리니...

 

그에 따른 부작용으로 '안예쁜', '의도한 바 없는' 애니메이션이 되버린 것이다.

 

 

 

비교해서 보자.

 

원하지 않은 결과물  이것이 내가 원한 그 것
 
 

 

 

 

로고의 영역이 없다가 생기니까 'by WANZARGEN' 문구가 위에 있다가 내려오는 것이고,

 

로고 이미지를 감싸고 있는 엘리먼트가 '가운데 정렬'인 상황에서,

 

엘리먼트들이 하나씩 늘어나니, 그에 따라 왼쪽으로 밀리는 것이다.

 

 

ㅠ_ㅠ

 

왜 이런걸 고려하지 않았을까.. 

 

 

 

솔루션

 
나는 뷰의 '커스텀 디렉티브'를 만들어 해결했다.
꼭 커스텀 디렉티브를 만들지 않더라도, v-if, v-show가 아닌 클래스 바인딩을 통해 opacity를 제어하여 해결 가능하다.
 
참고로 vuetifyjs 등 디자인 프레임웍을 이용해 해결하면 더 쉽고 빠르게 원하는 트랜지션을 만들 수 있을 것이지만..
나는 커스텀 디렉티브를 좀 더 심도있게 다뤄볼 겸 + 아주 라이트하고 특정한 상황에도 동작하는게 필요해서 직접 만들어 해결했다.
 
 
 
 
 
 
 
 
 
 
 
 
 

 

 

 

 

반응형