过渡路由

通过结合 Vue Router 中的 router-element 组件和过渡组件,我们可以轻松设置用户从一个 URL(路由)导航到另一个 URL(路由)时的过渡效果。

为了让您有更基本的理解,我们将在下一节中演示用户从网站主页重定向到网站上的 “关于” 页面的基本情况。

让我们用过渡包装 router-element 并添加 name="zoom" 属性:

<transition
    name="zoom"
    mode="out-in"
>
    <router-view/>
</transition>

这里我们将使用 mode 属性来指示过渡模式。目前有两种模式可以设置:

  • in-out:新元素首先出现,只有在此之后当前元素才会从视图中消失。

  • out-in:当前元素先出去,然后新元素才会进来。我们将以此作为示例,它比前一个更常见。

然后,我们只需要像往常一样使用过渡类设置过渡 CSS 效果即可。就那么简单:

/**Zoom animation **/
.zoom-enter-active,
.zoom-leave-active {
    animation-duration: 0.3s;
    animation-fill-mode: both;
    animation-name: zoom;
}

.zoom-leave-active {
    animation-direction: reverse;
}

@keyframes zoom {
    from {
        opacity: 0;
        transform: scale3d(0.4, 0.4, 0.4);
    }
    100% {
        opacity: 1;
    }
}

在本节中,我们研究了过渡路由。过渡效果是在路由渲染之间发生的动画,例如从一个页面导航到另一页面。在下一节中,我们将研究为应用程序中导航的每个路由创建过渡效果。

练习 7.03:为每条导航路由创建过渡效果

在本练习中,我们将使用 “过渡路由” 部分中的路由器元素来调整我们所学到的有关过渡的知识,以便为不同的路由创建不同的过渡效果。默认效果是淡入淡出(fade)。

要访问本练习的代码文件,请访问 https://packt.live/376DoXo

在开始本练习之前,请运行 vue create 命令来生成 Vue 入门项目。

  1. 使用 Vue Router 创建一个简单的应用程序,并使用位于 src/views/ 文件夹中的 Messages.vue 视图添加消息路由。使用上一个练习中的代码并在 App.vue 中添加指向此新创建的路由的链接。

  2. 接下来,我们在 App.vue 中用过渡组件包装 router-view 元素:

    <transition :name="transition" :mode="mode">
        <router-view/>
    </transition>
  3. 在 App.vue 的导出(export)部分中,确保 data 函数包含转换(transition)和模式(mode)的值,如下所示:

    data() {
        return {
            transition: 'fade',
            mode: 'out-in',
        };
    },
  4. 在 App.vue 中使用以下 CSS 添加淡入和淡出的 CSS 样式:

    <style>
    .fade-enter, .fade-leave-to {
        opacity: 0;
    }
    
    .fade-enter-active, .fade-leave-active {
        transition: opacity 1s ease-in;
    }
    </style>
  5. 此时,所有页面都加载了淡入淡出(fade)效果,甚至 /messages。但我们想让消息页面加载时具有不同的效果——缩放(zoom)效果。接下来,在同一样式(style)标签内添加缩放(zoom)动画的相关 CSS 代码:

    /**Zoom animation */
    .zoom-enter-active,
    .zoom-leave-active {
        animation-duration: 0.5s;
        animation-fill-mode: both;
        animation-name: zoom;
    }
    
    .zoom-leave-active {
        animation-direction: reverse;
    }
    
    @keyframes zoom {
        from {
            opacity: 0;
            transform: scale3d(0.4, 0.4, 0.4);
        }
        100% {
            opacity: 1;
        }
    }
  6. 现在,我们将借助以下代码为应用程序的默认布局添加一些标准 CSS 样式:

    #app {
        font-family: 'Avenir', Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
    }
    
    #nav {
        padding: 30px;
    }
    
    #nav a {
        font-weight: bold;
        color: #2c3e50;
    }
    
    #nav a.router-link-exact-active {
        color: #42b983;
    }
  7. 现在我们需要用这个特定的转换效果来映射 /messages 路由,并且不影响其它路由。为此,我们需要在 src/router/index.js 中的路由配置的元(meta)属性中添加一个名为 transition 的字段:

    {
        path: '/messages',
        name: 'messages',
        meta: {
            transition: 'zoom',
        },
        component: () => import(/* webpackChunkName: "about" */'../views/Messages.vue')
    }
  8. 检查 routes 对象的代码以确认其与以下代码相同。在这里,我们将应用程序的每个 URL 与视图文件进行匹配:

    const routes = [
        {
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/about',
            name: 'about',
            component: () => import(/* webpackChunkName: "about" */'../views/About.vue')
        },
        {
            path: '/messages',
            name: 'messages',
            meta: {
                transition: 'zoom',
            },
            component: () => import(/* webpackChunkName: "messages" */'../views/Messages.vue')
        }
    ]
  9. 这不会在浏览器中显示,因为此转换声明尚未绑定到 App.vue 组件的 data 字段,并且需要在视图开始加载之前绑定。为此,我们将利用第 6 章 “路由” 中提到的 create 生命周期钩子和 $router 全局的 beforeEach 路由钩子。

  10. 让我们在 App.vue 中每次路由更改之前添加一个钩子。我们会检查目的地路由(to)是否有自定义的 transition 效果。如果是,我们会将 App 实例中的 transition 值映射到它;否则,我们将在继续导航之前使用后备默认值,如下所示:

    created() {
        this.$router.beforeEach((
            to, // The destination route
            from, //The source route
            next //The function to trigger to resolve the hook
        ) => {
            let transition = 'fade';
            if (to.meta && to.meta.transition) {
                transition = to.meta.transition;
            }
            this.transition = transition;
            next();
        })
    }
  11. 使用以下命令运行应用程序:

    yarn serve
  12. 现在,如果您在浏览器中打开 localhost:8080 并导航到 /messages,您应该会看到类似于图 7.11 的内容:

image 2023 10 16 12 04 58 022
Figure 1. Figure 7.11: Navigating to /messages with a zoom effect in progress

当导航到其它路由时,我们应该看到如图 7.12 所示的默认 transition:

image 2023 10 16 12 05 57 326
Figure 2. Figure 7.12: Navigating to /home with a fade effect in progress

本练习演示了如何通过组合正确的钩子和方法,以最少的努力轻松地在不同页面上设置不同的转换。您可以进一步尝试使用外部库,以使您的应用程序动画更流畅、更生动。