通过 Vue Transitions 实现 Vue 组件的 CSS 动画效果 & 若干 Bug 修复


你会发现我们在之前的几篇重构教程中大量使用了 CSS 动画效果,比如通知框的弹出和消失、过滤器的滑出和隐藏、编辑表单的弹出和关闭、以及隐式菜单栏的滑出和隐藏等,这些动画效果有些是从左往右的,有些是从右往左的,有些是从上往下的,还有些是从中间向四周铺开,在 Vue 组件中实现这些动画效果很简单,下面我们就以表单提交成功后在页面顶部出现的通知组件 SuccessNotification.vue 为例来演示如何在 Vue 组件中实现 CSS 动画效果。

在 Vue 组件中应用 Vue Transitions 功能

如果你还不了解 Vue Transitions 功能,建议去官方文档快速了解下:https://cn.vuejs.org/v2/guide/transitions.html

简单来说,Vue Transitions 可以为我们在 Vue 中插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果(如动画、旋转、变形、淡入淡出等),对单元素的过渡效果来说,可以通过 transition 封装该组件来实现,同时通过 name 属性指定过渡效果名称:

<style lang="scss">
    @import '~@/abstracts/_variables.scss';

    div.success-notification-container {
        position: fixed;
        z-index: 999999;
        left: 0;
        right: 0;
        top: 0;
        div.success-notification {
            background: #FFFFFF;
            box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.12), 0 4px 4px 0 rgba(0, 0, 0, 0.24);
            border-left: 5px solid #00C853;
            height: 50px;
            line-height: 50px;
            margin: auto;
            width: 400px;
            margin-top: 150px;
            color: #242E38;
            font-family: "Lato", sans-serif;
            font-size: 16px;
            img {
                margin-right: 20px;
                margin-left: 20px;
            }
        }
    }
</style>

<template>
    <transition name="slide-in-top">
        <div class="success-notification-container" v-show="show">
            <div class="success-notification">
                <img src="/storage/img/success.svg"/> {{ successMessage }}
            </div>
        </div>
    </transition>
</template>

<script>

    import {EventBus} from '../../event-bus.js';

    export default {

        data() {
            return {
                successMessage: '',
                show: false
            }
        },

        mounted() {
            EventBus.$on('show-success', function (data) {
                this.successMessage = data.notification;
                this.show = true;

                setTimeout(function () {
                    this.show = false;
                }.bind(this), 3000);
            }.bind(this));
        }
    }
</script>

然后我们只需在 CSS 文件中定义如下两个样式即可在通知组件显示(enter)和隐藏(leave)的时候自动执行相应的过渡效果,这个样式名称命名规范就是 transitionname 属性值加上过渡的阶段名称(关于所有支持的过渡类名可以查看官方文档):

.slide-in-top-enter-active {
    // 显示时的动画效果
}

.slide-in-top-leave-active {
    // 隐藏时的动画效果
}

当然在 Roast 应用中,我们将对应的样式代码定义在了 resources/assets/sass/animations/_slide-in-top.scss 中以方便复用,然后在 resources/assets/sass/app.scss 中引入这个 CSS 动画文件。这样,编译前端资源后 SuccessNotification.vue 组件就可以在显示/隐藏时应用这个动画效果了。

从 Animista 下载动画效果 CSS 代码

这里要给大家推荐一个小技巧,那就是动画效果实现代码其实不需要我们自己去编写调试,我们可以从 Animista 这个网站去生成我们需要的动画效果实现代码并拷贝过来,Animista 这个网站为我们提供了大量常见的 CSS 动画实现效果,甚至支持自定义和预览效果,然后我们选择生成代码并拷贝过来即可。

slide-in-top 为例,我们在 Animista 上找到这个动画效果(http://animista.net/play/entrances/scale-in/scale-in-top):

点击右上角的「Generate code」图标,即可弹出对应的 CSS 实现代码:

我们将这两部分代码都拷贝到 resources/assets/sass/animations/slide-in-top.scss 中,然后结合我们的 Vue Transitions 将代码调整如下:

.slide-in-top-enter-active {
  -webkit-animation: slide-in-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
  animation: slide-in-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

.slide-in-top-leave-active {
  -webkit-animation: slide-in-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both reverse;
  animation: slide-in-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both reverse;
}

/* ----------------------------------------------
 * Generated by Animista on 2018-10-25 15:3:25
 * w: http://animista.net, t: @cssanimista
 * ---------------------------------------------- */

/**
 * ----------------------------------------
 * animation scale-in-top
 * ----------------------------------------
 */
@-webkit-keyframes slide-in-top {
  0% {
    -webkit-transform: translateY(-1000px);
    transform: translateY(-1000px);
    opacity: 0;
  }
  100% {
    -webkit-transform: translateY(0);
    transform: translateY(0);
    opacity: 1;
  }
}

@keyframes slide-in-top {
  0% {
    -webkit-transform: translateY(-1000px);
    transform: translateY(-1000px);
    opacity: 0;
  }
  100% {
    -webkit-transform: translateY(0);
    transform: translateY(0);
    opacity: 1;
  }
}

这样就完成了一个组件显示/隐藏时的动画效果,其他的几个动画效果实现思路也是完全一样,这里不再赘述,交给你们自己去玩吧。

至此,我们的项目重构系列教程就全部完成了,下面就这几天自己发现和大家反映的一些 Bug 的修复做一些简单的说明,所有修正后代码都已经提交到 https://github.com/nonfu/roastapp

项目若干 Bug 修复

城市下拉列表过滤器无效

首先我将城市过滤路由的 slug 参数调整为了 id,具体的代码修改细节可以看这里:https://github.com/nonfu/roastapp/commit/515418d5e887f2094638f7462cdc2f9e1a4d1a73

然后需要提出抱歉的之前的所有教程中把经纬度字段都搞反了,关于这一块代码的调整和城市过滤功能的实现可以查看这个代码提交记录:https://github.com/nonfu/roastapp/commit/7f6734d6dbd8ec32672f9d4a5eab11b417b41d9e

修正好以上代码之后,还要对数据表中的数据予以修复,主要是 cafes 表中经纬度字段的对调,以及 cities 表中经纬度字段值的补足,如果 cafes 表中历史数据 city_id 字段为空,也进行补足。

最后,运行 npm run dev 重新编译前端资源,在城市下拉列表选中某个城市,就会过滤该城市的咖啡店,并将地图缩放级别调整到该城市:

文本搜索过滤器报错

文本搜索框过滤器报错的修复代码位于这里:https://github.com/nonfu/roastapp/commit/086e3c1aae115d56fb6f45ad39618ac4c9519419,修正好代码重新编译前端资源后,就可以通过文本搜索过滤咖啡店了:

喜欢咖啡店后取消喜欢不显示

在咖啡店详情页喜欢该咖啡店后,还是显示喜欢文本,刷新后也无效,这个 Bug 的修复记录在这里:https://github.com/nonfu/roastapp/commit/d8fd819c55e98a71d0082abdc7554bde18424cba,修复完成后,刷新页面,就会显示出「已喜欢」的文本了:


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 功能模块重构 & CSS 整体优化:咖啡店详情页篇

>> 下一篇: 实现简单的、针对咖啡店增删改查的 RBAC 权限管理功能