记录一次公司内部的技术分享--vue过渡以及应用

163 阅读5分钟

背景

由于前端在平时的工作中会经常与页面打交道,在工作中往往按照设计师给定的设计图进行开发,而大多数时候,设计图并不会点出具体的实现的动效。这就导致很多时候我们做出来的东西失去活力,比如按钮的hover特效、背景的渐变特效等。而Vue框架本身就提供了一些api去做这样的工作,今天就由我跟大家一起去了解一下,vue列表过渡,会学习到关于Vue列表过渡的使用,以及对于列表过渡的封装实践。最后会给大家看一下我在平时的工作中对于列表过渡以及Vue动画的一些应用,以及我自己封装实现的列表过渡的方法和组件。

单元素和单组件的过渡

触发条件

条件渲染 (使用 v-if)

条件展示 (使用 v-show)

动态组件 component is (指挥系统中任务调度详情有使用到)

组件根节点 进行渲染组件的时候会触发

css类名

一共有6个,分别对应过渡的各个阶段。分别是v-enter、v-enter-active、v-enter-to、v-leave、v-leave-active、v-leave-to。对应的过程分别是过渡进入的开始状态、进入的生效状态、进入的结束状态、离开的开始状态、离开的生效状态、离开的结束状态;

当组件没有name属性的时候类名前缀会默认用v,当有name属性的时候前缀则用name属性的名称代替。

注:可以在写css的时候优先使用动画

钩子函数

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>

当需要在第一次渲染的时候就使用过渡,可以在组件添加一个appear属性;

标签只能用来包裹单元素, 严格说transition中不一定非得是单元素。也可以有多个元素,但是必须要使用v-if来控制其显隐。确保只能有一个处于显示状态的单元素。

无论是过渡还是动画,原理都是在特定的时间为transtion包裹的最外层元素添加和删除class名

为什么Vue知道动画或者过渡什么时候执行完了? 有什么办法去自己定义什么时候执行过渡?

多元素和多组件的过渡

多元素的过渡

多元素的过渡一般用v-if/v-else去实现,常见的用于判断一个列表里面的项为空的情况;

<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>Sorry, no items found.</p>
</transition>

当标签名相同的时候,最好是添加一个key值去区分,由于vue的内部机制,会只替换相同标签里的内容而不是整个标签进行替换

过渡模式

通过在transition添加mode属性.

in-out:新元素先进行过渡,完成之后当前元素过渡离开。

out-in:当前元素先进行过渡,完成之后新元素过渡进入。

<transition name="fade" mode="out-in">
  <!-- ... the buttons ... -->
</transition>

多组件的过渡

通过配合动态组件去实现

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>

在指挥的3.0任务调度中有使用到

列表过渡

应用

以下引用原文:原文 侵删

过渡的demo

动态跟进、段落列表、翻转列表、交错列表

// 动态跟进
@keyframes one-in {
            from {
                padding-top: 100px;
                height0%;
            }
            to {
                padding-top: 0px;
                height100%;
            }
        }
//段落列表
@keyframes one-in {
            from {
                padding-left100%;
            }
            to {
                padding-left0%;
            }
        }
//翻转列表
@keyframes one-in {
            from {
                height100%;
                transformrotateX(75deg);
            }
            to {
                height100%;
                transformrotateX(0deg);
                /* transform-origin: 145%, 0; */
            }
        }
//交错列表
@keyframes one-in {
            from {
                padding-left100%;
                height0;
            }
            to {
                padding-left0%;
                height: 100px;
            }
        }
        @keyframes two-in {
            from {
                padding-right100%;
                padding-top: 100px;
                height0;
            }
            to {
                padding-right0%;
                padding-top: 0px;
                height: 100px;
            }
        }

动态跟进列表

跟进列表是从下出现,回到初始位置,我在初始阶段采用了padding-top为100%,结束阶段为0%实现这个动画(margin-top也可以实现这个动画)

主要的实现代码:

// 动态跟进
@keyframes one-in {
            from {
                padding-top: 100px;
                height: 0%;
            }
            to {
                padding-top: 0px;
                height: 100%;
            }
        }

段落列表

段落列表是从右出现,回到正常位置,我在初始阶段采用了padding-left为100%,结束阶段为0%实现这个动画(margin-left也可以实现这个动画)

主要的实现代码:

//段落列表
@keyframes one-in {
            from {
                padding-left: 100%;
            }
            to {
                padding-left: 0%;
            }
        }

翻转列表

交错列表

交错列表稍微复杂点,不过我们可以分解为两个动画。

@keyframes one-in {
    from {
        padding-right: 100%;
        padding-top: 100px;
        height: 0;
    }
    to {
        padding-right: 0%;
        padding-top: 0px;
        height: 100px;
    }
}
@keyframes Two-in {
    from {
        padding-left: 100%;
        height: 0;
    }
    to {
        padding-left: 0%;
        height: 100px;
    }
}

然后根据列表渲染的index为奇数或偶数选择不同的动画

methods: {
    beforeEnter (el) {
        el.style.opacity = 0
    },
    enter (el, done) {
        let delay = el.dataset.index * 100
        let animation = el.dataset.index % 2 === 0
            ? 'one-in 0.4s infinite'
            : 'two-in 0.4s infinite'
        setTimeout(()=>{
            el.style.transition = 'opacity 0.4s '
            el.style.opacity = 1
            el.style.animation = animation
            el.style['animation-iteration-count'] = 1
            done()
        }, delay)
    }
}

创建可复用的过渡

过渡在3.0项目中的运用

1、示例 协同标会系统首页地图列表加载、主页地图分享列表

2、关于此封装的优缺点

优点: 可使v-for渲染的列表更具有活力

缺点:没有考虑到滚动条的防抖

疑问?为什么在vue项目中要使用asyn和await去设置每一条列表的动画?

滚动条闪烁的优化应该怎么做?

如果不用setTimeout去设置动画,还有没有更好的实现方式?

使用vue组件跟Vue过渡去重新封装这个组件的话,应该怎么去做?

因为Vue监听了目标元素【也就是transition标签包裹的最外层的这个元素】的transitionend和animationend这两个事件;

duration这个prop会强制的指定动画需要多少时间执行完毕,当指定了这个prop之后。就不再根据transitionend和animationend这两个事件来决定什么时候执行完毕然后删除class名了。时间一到就直接删除class名。如果duration指定的时间大于animation-duration或者tansition-duration,动画或者过渡执行完毕,也不会删除掉class名,而是等duration这个prop指定的时间结束之后再删除

github : github地址