⚡【有手就行】轻松封装一个超酷的FLIP动画组件

2,101 阅读6分钟

Why

渲染一个Table列表是非常非常常见的需求

如果我们什么都不做,只是单纯的增加或删除其中的一条内容

想想这时候整个列表会发生什么?

被增加或删除的元素会以“闪现”的方式出现或消失

更糟糕的是它的“兄弟们”也会跟着瞬间移动

对于一个但凡有轻微强迫症的前端攻城狮来说这实在是难以忍受的不是吗

Fine,我给每个列表项在恰当的时机添加/删除 CSS 类名

然后给这些class写上一些过渡或动画属性

这就完事了吗?

wait wait wait! 那"兄弟们"呢?

"兄弟们"依然还在瞬间移动啊

这....

难道要计算一下下一帧"兄弟们"应该在的位置

然后用transform移动过去并且给transform属性设置过渡?

呃呃呃woc想想就好麻烦啊🤯🤯🤯

就算费了九牛二虎之力实现了这个效果

但你会发现一个更糟糕的事情

“这也太卡了8😡😡😡”

你可能已经尝试过了改变元素的height、width、top、left或者除了transform和opacity之外的其他属性来实现一个动画效果。

或许你已经在以往的经历(做的动效)中发现自己的实现的动效有点粗糙甚至卡顿,其实这是有一定原因的🧐

任何触发布局变化的属性(比如height),浏览器都会递归检查布局中的其他元素是否也因此改变,这样的一个过程花销是很贵的

如果这个计算所费的时间比一个动画帧(大约16.7ms)更长,那么动画就会丢帧,从而导致动画迟滞

给用户的体验是,你的动画是卡顿的,这主要是因为动画丢的帧没有及时渲染。

要实现我们上面这个需求

我们就需要用到一个狂拽酷炫吊炸天的动画思想:FLIP

“但是我不懂FLIP是什么鬼啊怎么办”

Hold on~

强大的Vue贴心地给我们提供了两个内置组件: transition & transition-group 🤩🤩

transition可能你就用得多了
但它不是今天的主角,不谈~

transition-group内部实现了一个FLIP的简单动画队列
事实上,贴心的官网上也有对它的介绍和 demo🤞

今天我们就利用transition-group封装一个通用的组件
目的是只要往里面丢一个列表就可以帮我们实现酷炫的FLIP动画效果了🥂



How

Talk is cheap, show you the code

FLIPWrapper.vue

<template>
  <transition-group name="FLIP-wrapper" id="FLIP-wrapper">
    <slot>
      <h1 :key="-1" class="FLIP-wrapper-tip">🦄 EMPTY 😱😱😱😱😱😱😱</h1>
    </slot>
  </transition-group>
</template>

<script>
export default {
  name"FLIPWrapper"
};
</script>

<!--注意这里的style不能用scoped,否则过渡效果会失效-->
<style>
.FLIP-wrapper-enter-active,
.FLIP-wrapper-leave-active {
  transition: all 0.5s ease;
}

.FLIP-wrapper-leave-active {
  position: absolute;
}

/*元素进入前和离开后的相关样式*/
.FLIP-wrapper-enter.FLIP-wrapper-leave-to
  /* .component-fade-leave-active for below version 2.1.8 */
 {
  opacity0;
  transformtranslateY(-100%scale(0.1);
}

/*使用move class触发FLIP,让兄弟元素产生过渡效果*/
.FLIP-wrapper-move {
  transition: transform 1s, opacity 2s;
}
</style>

<style scoped>
#FLIP-wrapper {
  display: flex;
  width100%;
  flex-wrap: wrap;
}

/*
  下面是slot默认内容的一些样式
  这部分不重要
*/
.FLIP-wrapper-tip {
  margin-left8px;
  color#a3a3a3;
  font-weight: bold;
  border-radius8px;
  padding1em 1.5em;
  border2px solid transparent;
  backgroundlinear-gradient(white, white) padding-box,
    repeating-linear-gradient(
        -45deg,
        #a3a3a3 0,
        #a3a3a3 25%,
        transparent 0,
        transparent 50%
      )
      0 / 0.6em 0.6em;
  animation: ants 12s linear infinite;

  width100%;
}
@keyframes ants {
  to {
    background-position100% 100%;
  }
}
</style>




使用

<FLIPWrapper>
        <div v-for="(people, index) in peopleList" :key="people.id">
            // do everything you want...
        </div>
</FLIPWrapper>



效果

coolcoolcoolcoolcool...







What

FLIP的效果很不错吧~

FLIP就是以这样一种高性能的方式来动态的改变DOM元素的位置和尺寸,而不需要管它的布局是如何计算或渲染的(比如,height、width、float、绝对定位、Flexbox和Grid等)。在改变的过程中将赋予一定的动效,从而达到我们所需要的目的,让UI动效更为合理,相应增强用户的体验

那么FLIP是什么意思呢?


FLIP是一种记忆设备和技术,最早是由@Paul Lewis提出的,FLIP是FirstLastInvertPlay四个单词首字母的缩写。

First

First指的是在任何事情发生之前(过渡之前),记录当前元素的位置、尺寸、透明度等等的样式状态信息



Last

Last指的是执行一段代码,让元素发生相应的变化,并记录元素在最后状态的位置、尺寸、透明度等等的样式状态信息



Invert

Invert指的是计算元素第一个位置(first)和最后一个位置(last)之间的位置变化(如果需要,还可以计算两个状态之间的尺寸大小的变化),然后使用这些数字做一定的计算,让元素进行移动(通过transform来改变元素的位置和尺寸),从而创建它位于第一个位置(初始位置)的一个错觉



Play

Play指的是将元素反转(假装在first位置),我们可以把transform设置为none,将其移动到last位置,让元素有动画效果



写在最后

正如@Nick Babich所说:动画将用户界面带入生活

感谢FLIP给前端工作者们带来了这么一把利刃
让我们可以以极小的成本去打造更为极致的用户体验 👏👏👏


另外,如果对FLIP的实现感兴趣的话可以看看国外的一个专栏博客:FLIP

以及掘金社区内一位大佬写的挺不错的关于FLIP实现的文章: 前端动画必知必会:React 和 Vue 都在用的 FLIP 思想实现小姐姐流畅移动。


感谢你的耐心阅读🤞🤞🤞

听说喜欢点赞⭐的人运气总不会太差