Vue列表过渡交换位置的鬼畜表现

1.需求

--官方文档 列表的排序过渡
不多说,官方文档已经写得很明白。

项目中需要实现的功能是,根据时间线展示数据,一年的数据分为12个月,每个月内不同指标的数据占比排序,有进度条,数值大小,百分比等。
每一个月的数据变化,代表着排序出现变化,所以用到了Vue的列表交换位置效果。

2.表现

一开始,其实没问题,很顺利的交换了位置,只要把每个月份的数据依次填充到list,数据驱动视图的改变,虽然交换的速度很快。
但是,这样直接展示数据,效果太差,没有逼格,产品觉得还可以做得更好,比如:

  • 进度条的长度不要一下子就改变完成,要有一个过渡效果
好的,我加一个过渡效果,{transition-duration: .3s;}
  • 数值的变化也需要一个变化效果,不要从10直接飙到100,得11,12,13,……,100
这是什么操作?一定要做么?能不能不做?好吧,我做!!!

怎么做呢?
月份的切换,设定为5秒切换一次。
5秒之内,不断的修改数据,对应的value从上一个月份自增到下一个月份,同样还是数据驱动视图刷新,css{transition-duration: .3s;}都是多余的,删掉,OK!

然鹅,鬼畜出现了。
数据没问题,过渡效果棒棒的。
但是位置交换的时候,就跟发羊癫疯,又像帕金森,磕多了炫迈,停不下来。

WTF?

还能不能好好的搬砖?

3.分析

其实没什么好分析的,代码就这几行。
数据驱动视图刷新,肯定是数据更新造成的。

但是为什么数据更新会造成排序交换位置出问题呢?
已经设定了5秒钟才交换一次位置。

找不到原因,就无法解决这个bug。
看来,还是得分析Vue的交换位置逻辑。
官方文档读了几遍,终于,找到了关键字:FLIP

在Vue中,交换位置的时候,其实不是真正的交换位置,毕竟列表中大部分的DOM元素是重用的,只是文字节点内容改变。
而实现交换效果的逻辑是:
假设列表有4个元素,依次排列a,b,c,d。
当排序发生变化的时候,顺序为b,a,c,d。
通过el.getBoundingClientRect()获得a元素和b元素的位置差,添加特定的class,这个class设定了元素的变形过渡时间:

.flip-list-move {
  transition: transform 1s;
}

然后计算出位置差invert,通过设定变形效果el.style.transform = translateY(${invert}px),造成a,b,c,d依然在旧的位置的效果,然后移除变形设置,el.style = ''
因为这时候a,b,c,d的数据已经交换完成,元素回归原位置,看起来就像是从旧的位置直接来到新的位置。

过程有4个:

  • 数据交换,添加缓动样式flip-list-move
  • 排序,通过el.style.transform = translateY(${invert}px)把交换后的数据设置成交换前的效果
  • 移除变形,el.style = '',元素开始回归原位,但是看起来是跑到新的位置,这是重点
  • 交换完成,移除缓动样式flip-list-move

结语

之前一直有使用Vue的过渡效果,但是从来没有分析过实现的逻辑,这次终于踩到了巨坑。
很是不幸!
通过这次的分析,算是掌握了新的知识,原来可以这么玩!

但是,WTF,这个需求该怎么做???

已实现的github demo

你可能感兴趣的