利用vue transition组件实现微信路由滑入滑出效果

262 阅读1分钟

概述

再微信当中,点击朋友圈,然后点击返回,会有一个友好的路由过度效果,看起来还是很舒适的,除开微信,其实很多移动端的app应用都有这个功能,现在记录一下vue项目中h5实现类似的效果。

实际项目效果图

项目体验地址:develop.kingchannels.cn:50609/h5 动画.gif

准备工作

要做这个动画效果,你需要对vue的内置transition组件有使用经验,如果没用过的话,建议自己根据官网的示例自己去试试。

实现

1.首先你需要准备多个路由页面,这里演示使用,只新建两个页面,一个充当首页(home),一个充当详情(detai)。

./pages/Detail.vue

<template>
  <div class="page detail">
    <p>详情页面</p>
    <button @click="$router.back()">返回home页面</button>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  components: {},
};
</script>

<style lang="less">
.detail {
  background-color: #008c8c;
}
</style>

./pages/Home.vue

<template>
  <div class="page home">
    <p>首页</p>
    <button @click="$router.push('/detail')">到detial页面</button>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  components: {},
};
</script>

<style lang="less">
.home {
  background-color: pink;
}
</style>

./router/index.js

import Vue from "vue";
import VueRouter from "vue-router";
import store from "../store/index";
Vue.use(VueRouter);
const router = new VueRouter({
  routes: [
    {
      path: "/",
      redirect: "/home",
    },
    {
      path: "/home",
      component: () => import("../pages/Home.vue"),
      meta: {
        index: 1,
      },
    },
    {
      path: "/detail",
      component: () => import("../pages/Detail.vue"),
      meta: {
        index: 2,
      },
    },
  ],
});

// 设置路由切换动画,通过meta中定义层级关系
Vue.prototype.setoRouteTransitionName = function (to, from) {
  let transitionName = "";
  if (to.meta.index > from.meta.index) {
    transitionName = "slide-l"; // 向左滑动
  } else if (to.meta.index < from.meta.index) {
    // 由次级到主级
    transitionName = "slide-r";
  } else {
    transitionName = ""; // 同级无过渡效果
  }
  store.commit("setTransitionName", transitionName);
};
router.beforeEach((to, from, next) => {
  Vue.prototype.setoRouteTransitionName(to, from);
  next();
});
export default router;

./store/index.js 通过状态管理动态设置transitionname

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
  //动态控制动画name属性
    transitionName: "slide-l",
  },
  mutations: {
    setTransitionName(state, data) {
      state.transitionName = data;
    },
  },
});

./App.vue

<template>
  <div class="app">
    <!-- <transition :name="transitionName">
      <router-view></router-view>
    </transition> -->
    <transition name="slide-l">
      <router-view></router-view>
    </transition>
  </div>
</template>

<script>
import { mapState } from "vuex";

export default {
  computed: {
    ...mapState(["transitionName"]),
  },
};
</script>

<style lang="less">
html,
#app,
body,
.page,
.app {
  height: 100%;
  width: 100%;
  color: #fff;
}
.page {
  text-align: center;
  button {
    color: #fff;
    background-color: green;
    width: 200px;
    height: 50px;
    margin-top: 300px;
  }
}
//定义过度动画
.slide-l-enter-active,
.slide-l-leave-active,
.slide-r-enter-active,
.slide-r-leave-active {
  transition: all 0.6s;
  height: 100%;
  width: 100%;
  position: absolute;
  left: 0;
  top: 0;
}
//左滑过度
.slide-l-enter {
  opacity: 0;
  transform: translateX(100%);
}
.slide-l-enter-to,
.slide-l-leave {
  opacity: 1;
  transform: translateX(0);
}
.slide-l-leave-to {
  opacity: 0;
  transform: translateX(-100%);
}
//右滑过度
.slide-r-enter {
  opacity: 0;
  transform: translateX(-100%);
}
.slide-r-enter-to,
.slide-r-leave {
  opacity: 1;
  transform: translateX(0);
}
.slide-r-leave-to {
  opacity: 0;
  transform: translateX(100%);
}
</style>

最终效果

动画.gif