본문 바로가기
Javascript

[Vue js 반응형 웹페이지] 페이지 전환효과(fade, slide) *router 사용

by YoYoHa 2021. 5. 10.
728x90
반응형

*하이브리드 앱, 네이티브 앱 만들어보면서 페이지 전환효과의 중요성을 알게됐음

그래서 필요한 페이지 전환효과를 찾아봄

 

목표

1. page1, page2, page3은 슬라이드 전환

2. 목표1, page4, page5는 fade 전환

 

 

 

모듈설치

npm install --save vue-router

npm install jquery --save

npm i -g npm-check-updates

 

 

App.vue

<template>
  <div id="app">
    <nav>
      <router-link :to="{name: 'page1'}">Slide Page</router-link>
      <router-link :to="{name: 'page4'}">New Page 1</router-link>
      <router-link :to="{name: 'page5'}">New Page 2</router-link>
    </nav>
    <main>
      <transition :name="transitionName">
        <router-view />
      </transition>
    </main>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      transitionName: ""
    };
  },
  watch: {
    $route(to, from) {
      if(to.meta.page == null || from.meta.page == null){
        this.transitionName = "fade";
      }else{
        this.transitionName = to.meta.page > from.meta.page ? "next" : "prev";
      }
      console.log(this.transitionName);
    }
  }
};
</script>

<style>
* { box-sizing: border-box; }
html, body { height: 100%; margin:0; padding:0; }
#app { display: grid; grid-template-rows: min-content; min-height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #FAFAFA; }
nav { display: flex; align-items: center; justify-content: space-around; background-color: #424242; position: sticky; bottom: 0; z-index: 1; }
a { color: white; text-decoration: none; text-transform: uppercase; font-weight: bold; padding: 1em 0; margin: 0 1em; border-bottom: 2px solid transparent; }
a.router-link-exact-active { border-color: inherit; }
main h1{ color:black; }
main { min-height: 100%; display: grid; grid-template: "main"; flex: 1; background-color: white; position: relative; z-index: 0; overflow-x: hidden; }
main > * { grid-area: main; background-color: white; position: relative; }
main > :first-child { z-index: 1; }

/* 전환효과 (Slide) */
.next-leave-to { animation: leaveToLeft 500ms both cubic-bezier(0.165, 0.84, 0.44, 1); z-index: 0; }
.next-enter-to { animation: enterFromRight 500ms both cubic-bezier(0.165, 0.84, 0.44, 1); z-index: 1; }
.prev-leave-to { animation: leaveToRight 500ms both cubic-bezier(0.165, 0.84, 0.44, 1); z-index: 1; }
.prev-enter-to { animation: enterFromLeft 500ms both cubic-bezier(0.165, 0.84, 0.44, 1); z-index: 0; }
@keyframes leaveToLeft { from { transform: translateX(0); } to { transform: translateX(-25%); filter: brightness(0.5); } }
@keyframes enterFromLeft { from { transform: translateX(-25%); filter: brightness(0.5); } to { transform: translateX(0); } }
@keyframes leaveToRight { from { transform: translateX(0); } to { transform: translateX(100%); } }
@keyframes enterFromRight { from { transform: translateX(100%); } to { transform: translateX(0); } }

/* 전환효과 (Fade) */
.fade-enter-active, .fade-leave-active { transition: opacity .8s; }
.fade-enter, .fade-leave-to { opacity: 0; }
</style>

 

 

page1.vue

<template>
  <section>
    <h1>SLIDE 1</h1>
    <button>
      <router-link :to="{name: 'page2'}">next</router-link>
    </button>
  </section>
</template>

<style scoped>
a{ color:black; }
section { display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: Lightyellow; }
</style>

 

 

page2.vue

<template>
  <section>
    <h1>SLIDE 2</h1>
    <div>
      <button>
        <router-link :to="{name: 'page1'}">prev</router-link>
      </button>
      <button>
        <router-link :to="{name: 'page3'}">next</router-link>
      </button>
    </div>
  </section>
</template>

<style scoped>
button{ margin:0 10px; }
a{ color:black; }
section { display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: Lightblue; }
</style>

 

 

page3.vue

<template>
  <section>
    <h1>SLIDE 3</h1>
    <button>
      <router-link :to="{name: 'page2'}">prev</router-link>
    </button>
  </section>
</template>

<style scoped>
a{ color:black; }
section { display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: LightGreen; }
</style>

 

 

page4.vue

<template>
  <section>
    <h1>NEW PAGE 1</h1>
  </section>
</template>

<style scoped>
section { display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: Lightgray; }
</style>

 

 

page5.vue

<template>
  <section>
    <h1>NEW PAGE 2</h1>
  </section>
</template>

<style scoped>
section { display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: #CEECF5; }
</style>

 

 

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

 

 

route.js

import Vue from "vue";
import Router from "vue-router";
import Page1 from "./views/page1";
import Page2 from "./views/page2";
import Page3 from "./views/page3";
import Page4 from "./views/page4";
import Page5 from "./views/page5";

Vue.use(Router);

export default new Router({
    mode: "history",
    routes: [
        {
            path: "/",
            name: "page1",
            component: Page1,
            meta: {
                page: 1
            }
        },
        {
            path: "/page2",
            name: "page2",
            component: Page2,
            meta: {
                page: 2
            }
        },
        {
            path: "/page3",
            name: "page3",
            component: Page3,
            meta: {
                page: 3
            }
        },
        {
            path: "/page4",
            name: "page4",
            component: Page4,
            transitionName: 'fade'
        },
        {
            path: "/page5",
            name: "page5",
            component: Page5,
            transitionName: 'fade'
        }
    ]
});

 

 

 

Result

 

728x90
반응형

댓글