vue.jsvuejs3vue-routervue-transitions

Vue 3 Page transition : how to have the next page already in place and reveal it with a swipe?


I'm trying to make a page transition with vue router in Vue 3

This image sums up what I'm trying to do

I'm building a website with different pages (on the image: blue zone) that all have a scroll and a common fixed navigation bar at the top. If you click on one of the links of the topbar, it should move the entire page container to the bottom by 100vh to reveal a special view (on the image: red zone)

My problem

I've been trying different things for a few days:

My questions

Thank you for reading


Solution

  • I hope this idea can help you.

    Since page is just a component that changed on redirect, you can create a page that contains both of your pages. For example, according to your pictures, I'll have 2 pages (Red and Blue). Then, I'll create Merge that contains Red and Blue

    This is Red.vue

    <template>
      <div class="red-page">
        Red page
        <div style="height: 200px" />
        <div class="link" @click="$emit('redirect')">To blue</div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'Red',
      emits: ['redirect'],
    };
    </script>
    
    <style>
    .red-page {
      background-color: red;
      height: 100vh;
      color: white;
    }
    
    .link {
      cursor: pointer;
      color: white;
    }
    </style>
    

    This is Blue.vue

    <template>
      <div class="blue-page">
        <div class="header" />
        <!-- Any content -->
        <div style="height: 700px" />
        <div class="link" @click="$emit('redirect')">To red</div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'Blue',
      emits: ['redirect'],
    };
    </script>
    
    <style>
    .blue-page {
      background-color: blue;
      height: 1000px;
    }
    
    .header {
      background-color: yellow;
      height: 50px;
      position: fixed;
      width: 90vw;
    }
    
    .link {
      cursor: pointer;
      color: white;
    }
    </style>
    

    This is Merge.vue

    <template>
      <div>
        <Red
          style="position: fixed; height: 100vh; width: 100vw; z-index: -9999"
          @redirect="redirect(false)"
        />
        <Transition name="slide-down">
          <Blue v-if="isBlue" @redirect="redirect(true)" />
        </Transition>
      </div>
    </template>
    
    <script>
    import Blue from './Blue.vue';
    import Red from './Red.vue';
    
    export default {
      name: 'Merge',
      components: { Blue, Red },
    
      data: () => ({
        isBlue: true,
      }),
    
      methods: {
        redirect(toRed) {
          this.isBlue = !toRed;
          history.pushState({}, null, this.isBlue ? '/blue' : '/red');
        },
      },
    
      created() {
        this.isBlue = this.$route.path === '/blue';
      },
    };
    </script>
    
    <style>
    .slide-down-enter-active {
      transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
    }
    
    .slide-down-leave-active {
      transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
    }
    
    .slide-down-enter-from,
    .slide-down-leave-to {
      transform: translateY(1000px);
    }
    </style>
    

    Put both Red and Blue inside Merge. Then wrap Blue with <Transition/>. By this, you can add transition to Blue and make it slide down to reveal Red. Finally, inside Red and Blue, emit some signal when you try to redirect

    The detail is here: https://stackblitz.com/edit/vue-fyebnk

    In this example, I've made Blue slides down when go to Red and slides up when go back from Red to Blue.

    In Blue, you can see Red is rendered when you look at Blue right side. But it up to you to modify it since loading Red first can be wasting if user is not gonna use it.

    And of course, the transition can only occur if you click link inside Blue or Red. Any other redirect method will just immediately show Blue or Red

    Beside, if library is a way to go. I think you should have a look at RevealJS or sli.dev

    Good luck to you