e

ec50n9

V1

2023/01/24阅读:28主题:嫩青

vue-router + gsap 跨组件动画实现

假设有/foo/bar两个页面,两个页面里面都有一个div.me元素,它们两者是独立的,大概长这样:

组件结构
组件结构

/foo跳转到/bar的过程分为如下几步:

跳转过程
跳转过程
  1. /foodiv.me中获取关键关键样式
  2. onBeforeRouteLeave中把样式键值存到to.query
  3. 跳转到/bar
  4. /bar页面的onMounted()中使用useRoute()获取传过来的样式键值
  5. 使用gsap.from来为/bar中的div.me增加变化动画

大概就这个思路,实现起来也很简单:

首先在/foo页面加上跳转链接和需要变换的组件:

<template>
    <div>
        <RouterLink to="/bar">go to bar</RouterLink>
        <TheImage class="the-img" />
    </div>
</template>

接下来是js部分:

<script setup>
import gsap from 'gsap';
import { reactive, onMounted } from 'vue';
import { onBeforeRouteLeave, useRoute } from 'vue-router';
import TheImage from '../components/TheImage.vue';

const style = reactive({
    width"10rem",
    height"10rem",
    color"#000",
    backgroundColor"#000"
})
  
// 跳转时判断目的地是不是 foo 页面,如果是的话就把把数据一同传递过去
onBeforeRouteLeave((to) => {
    if (to.name === "bar") to.query = { ...style }
})
</script>

这里使用了reactive来创建一个响应式的sytle对象,而非普通对象。接下来设置组件的样式:

<style scoped>
.the-img {
    widthv-bind('style.width');
    heightv-bind('style.height');
    colorv-bind('style.color');
    background-colorv-bind('style.backgroundColor');
}
</style>

⚠️ 需要注意的是,我这里使用了to.name来进行判断,前提是路由配置中手动声明了路由的name,比如我这里就是:

const routes = [
  {
    path"/",
    component()=>import("../App.vue"),
    children: [
      {
        // 这里👇
        name"foo",
        path"foo",
        component()=>import("../pages/Foo.vue")
      },
      {
        // 还有这里👇
        name"bar",
        path"bar",
        component()=>import("../pages/Bar.vue")
      }
    ],
  },
];

接下来就是/bar页面,htmlcss部分和前面的一样,js代码如下:

<script setup>
import gsap from 'gsap';
import { reactive, onMounted } from 'vue';
import { onBeforeRouteLeave, useRoute } from 'vue-router';
import TheImage from '../components/TheImage.vue';

const style = reactive({
    width"10rem",
    height"10rem",
    color"#000",
    backgroundColor"#000"
})

// 页面加载好之后,如果有传进来参数,就使用 gsap 来进行动画过渡
onMounted(() => {
    const route = useRoute()
    route.query && gsap.from(style, route.query)
})
</script>

这样就完成一个动画跳转了,但是还需要返回,我希望返回的时候动画也会逆转过来运行。其实也很简单,在/foo页面加上onMounted()那些逻辑,并且在/bar页面加上onBeforeRouteLeave()的逻辑即可:

// foo.vue
import gsap from 'gsap';
import { reactive, onMounted } from 'vue';
import { onBeforeRouteLeave, useRoute } from 'vue-router';
import TheImage from '../components/TheImage.vue';

const style = reactive({
    width"10rem",
    height"10rem",
    color"#000",
    backgroundColor"#000"
})

onMounted(() => {
    const route = useRoute()
    route.query && gsap.from(style, route.query)

})
onBeforeRouteLeave((to) => {
    if (to.name === "bar") to.query = { ...style }
})
// bar.vue
import gsap from 'gsap';
import { reactive, onMounted } from 'vue';
import { onBeforeRouteLeave, useRoute } from 'vue-router';
import TheImage from '../components/TheImage.vue';

const style = reactive({
    width"10rem",
    height"10rem",
    color"#000",
    backgroundColor"#000"
})

onMounted(() => {
    const route = useRoute()
    route.query && gsap.from(style, route.query)

})
onBeforeRouteLeave((to) => {
    if (to.name === "foo") to.query = { ...style }
})

稍微观察一下就可以发现,其实两份代码只有倒数第二行的to.name === "..."不一样而已。

总结

这种方式实现跨组件动画有比较明显的缺点,就是两个组件为独立的组件。

因为这里只是人为的使它们看起来像而已。如果这个组件内部有状态,页面跳转后得手动传这些状态进去手动加上去,这是很不方便的。

以上。

分类:

前端

标签:

Vue.js

作者介绍

e
ec50n9
V1