vue quickly configure routing animation and cache

vue quickly configure routing animation and cache

preface

When using vue to route animation and cache, some problems are encountered, such as:

  1. Generate animation correctly;
  2. Animation can be generated conditionally, for example, animation is used from page A to page B, and animation is not used from page A to other pages;
  3. Conditional cache, manage cache
  4. Simultaneous use of animation and cache

Here I make a summary of what I can think of.

The following contents have been written into a plug-in to facilitate rapid configuration, and the method of judging forward and backward has been added. github address:

vue-router-cache-animate

Routing animation

How to animate

<template>
  <div id="app">
    <header></header>
    <!-- use transition Include the container of the switching component page -->
    <transition name="slide">
      <router-view></router-view>
    </transition>
  </div>
</template>

When the route is switched, the essence of the animation is to add the next route node (nextNode) after the curnode rendered by the route view.

curNode executes the exit animation and nextNode executes the entry animation. Since curNode and nextNode are sibling nodes, if you want to realize right in and left out, you need to add absolute positioning.

/* Enter animation */
.slide-enter {
  opacity: 0;
  transform: translate(100%, 0);
}

.slide-enter-active,
.slide-leave-active {
  transition: transform 0.2s ease;
  position: absolute;
}

/*Leave animation*/
.slide-leave-to {
  transform: translate(-100%, 0);
}

#app {
  overflow-x: hidden;
  overflow-y: auto;
}

If the element goes right beyond the window, a horizontal scroll bar will appear on the page, so you need to add overflow:hidden for the parent element.

Of course, you can also use fixed positioning without scroll bars.

Dynamic transition

Dynamically set the animation effect according to the route information. For example, route a to route B uses the left sliding effect, and route b back to route a uses the right sliding effect.

<!-- Use dynamic transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
export default {
  watch: {
    $route(to, from) {
      const toName = to.name
      const fromName = from.name
      if (fromName === 'a' && toName === 'b') {
        this.transitionName = 'slide-left'
      } else if (fromName === 'b' && toName === 'a') {
        this.transitionName = 'slide-right'
      }
    }
  }
}

The peer route has no animation, and the parent route to the sub route has animation (the opposite animation when returning). For example, click the article in the article list to enter the article details page, and the article details page has a return button to return to the list.

<!-- Use dynamic transition name -->
<transition :name="transitionName" :css="css">
  <router-view></router-view>
</transition>
export default {
  watch: {
    $route(to, from) {
      if (to.meta.child && from.meta.parent) {
        this.transitionName = 'slide-left'
        this.css = true
      } else if (to.meta.parent && from.meta.child) {
        this.transitionName = 'slide-right'
        this.css = true
      } else {
        this.transitionName = ''
        this.css = false
      }
    }
  }
}
.slide-right-enter {
  transform: translate(-100%, 0);
}

.slide-right-enter-active,
.slide-right-leave-active {
  transition: transform 0.3s ease;
  position: fixed;
  width: 100%;
  box-sizing: border-box;
}

.slide-right-leave-to {
  transform: translate(100%, 0);
}

.slide-left-enter {
  transform: translate(100%, 0);
}

.slide-left-enter-active,
.slide-left-leave-active {
  transition: transform 0.3s ease;
  position: fixed;
  width: 100%;
  box-sizing: border-box;
}

.slide-left-leave-to {
  transform: translate(-100%, 0);
}

Even if the name of the transition is empty, it will flicker. At this time, you need to set the css of the transition to false.

More details can be viewed vue routing transition.

Route cache

Cache specific routes

<keep-alive include="Route rendered components name option">
  <router-view></router-view>
</keep-alive>

You can use keep alive's include and exclude to conditionally cache routes.

Or define routing metadata to conditionally cache:

{
    path:'/Distribution',
    name:'Distribution',
    component: Distribution,
    meta: {keepAlive: true } // cache
 }

<keep-alive>
  <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive"></router-view>

However, due to the use of v-if, the route animation with the transition component cannot succeed.

Dynamic cache

Sometimes it only needs to be cached at specific times, such as page a (corresponding to component a) to page B (corresponding to component B), and it is not cached at other times.

You can dynamically set the include value of keep alive.

<transition :name="transitionName" :css="css">
  <keep-alive :include="keepAlive">
    <router-view />
  </keep-alive>
</transition>

keepAlive is an array that holds the name of the component that needs to be cached. The cache component needs to provide the name option.

Use vuex or root instance data to store global keepAlive.

In component a, the route leaves the guard, and keepAlive is dynamically modified according to the next route

beforeRouteLeave(to, from, next) {
  // Both a - > b and B - > a need to cache component A
  if (
    (from.name === "a" && to.name === "b") ||
    (from.name === "b" && to.name === "a")
  ) {
    // Setting keepAlive method of vuex
    this.storeSetKeepAlive(["A"]);
  } else {
    this.storeSetKeepAlive(["None"]);
  }
  setTimeout(() => {
    next();
  });
}
  1. Here, a delay function setTimeout is used to ensure that the root component using router view gets the keepAlive value before jump. (watch is asynchronous)
  2. At the same time, for no component cache, do not set keepAlive = [], so that all components will be cached.

Do not destroy components to make components not cached, similar to the following:

  beforeRouteLeave (to, from, next) {
    if(to.name !== 'b'){
      this.$destroy()
    }
  }

All routes are cached, but this component is destroyed when routing to b.

Once used in this way, route a to route b will also be cached, but after returning route a from route b, the cached a component will not be used, but a component a will be re rendered.

Global management cache

Manually inject beforeroutleave into each routing component. When the project is huge, it will be difficult to maintain. The cache status can be managed uniformly by global blending:

Vue.mixin({
  beforeRouteLeave(to, from, next) {
    if (from.meta.keepAlive && to.meta.keepAlive) {
      // Root instance store keepAlive
      this.$root.keepAlive = ['A']
    } else {
      this.$root.keepAlive = ['None']
    }
    setTimeout(() => {
      next()
    })
  }
})

Simultaneous animation and caching

Requirements:

  1. Primary routing and secondary routing
  2. There is animation from level-1 route to level-2 route (slide left to enter), and level-2 route can return to level-1 route (slide right to leave)
  3. When the secondary route returns, the cached primary route page is displayed
  4. There is no animation between level-1 route and level-1 route, and there is no cache
  1. Define routes, add metadata parent to all primary routes, and add metadata child to secondary routes

    const router = new Router({
      routes: [
        {
          path: '/a',
          component: A,
          meta: {
            parent: true
          }
        },
        {
          path: '/b',
          component: B,
          meta: {
            child: true
          }
        }
      ]
    })
    
  2. Cache the array and save it to the data of the root instance

    new Vue({
      router,
      store,
      i18n,
      data: {
        keepAlive: []
      },
      render: h => h(App)
    }).$mount('#app')
    
  3. Add the name option for each routing component, here are A and B respectively

  4. Global blend in beforeRouteLeave guard

    Vue.mixin({
      beforeRouteLeave (to, from, next) {
        // From level-1 route to level-2 route, cache when level-2 route to level-1 route
        if (from.meta.parent && to.meta.child || from.meta.child && to.meta.parent) {
          this.$root.keepAlive = ['A']
        } else {
          this.$root.keepAlive = ['None']
        }
        setTimeout(() => {
          next()
        })
      }
    })
    
  5. Use both transition and keep alive

    <div id="app">
      <transition :name="transitionName" :css="css">
        <keep-alive :include="$root.keepAlive">
          <router-view />
        </keep-alive>
      </transition>
    </div>
    
  6. Observe routing information and animate dynamically

    export default {
      watch: {
        $route(to, from) {
          if (to.meta.child && from.meta.parent) {
            this.transitionName = 'slide-left'
            this.css = true
          } else if (to.meta.parent && from.meta.child) {
            this.transitionName = 'slide-right'
            this.css = true
          } else {
            this.transitionName = ''
            this.css = false
          }
        }
      }
    }
    
    #app {
      height: 100%;
      position: relative;
      overflow: hidden;
    }
    
    .slide-right-enter {
      transform: translate(-100%, 0);
    }
    
    .slide-right-enter-active,
    .slide-right-leave-active {
      transition: transform 0.3s ease;
      position: absolute;
      width: 100%;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      box-sizing: border-box;
    }
    
    .slide-right-leave-to {
      transform: translate(100%, 0);
    }
    
    .slide-left-enter {
      transform: translate(100%, 0);
    }
    
    .slide-left-enter-active,
    .slide-left-leave-active {
      transition: transform 0.3s ease;
      position: absolute;
      width: 100%;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      box-sizing: border-box;
    }
    
    .slide-left-leave-to {
      transform: translate(-100%, 0);
    }
    

Effect demonstration:

)

Tags: Vue.js

Posted by mrbill501 on Sat, 14 May 2022 20:51:20 +0300