欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何在Vue中实现Svelte的Defer Transition

程序员文章站 2022-04-26 09:06:23
最近观看了rich harris的视频,惊叹于svelte框架的高效同时,还发现了vue所不具备的一些关于动画的原生支持—defer tran...

最近观看了rich harris的<rethinking reactivity>视频,惊叹于svelte框架的高效同时,还发现了vue所不具备的一些关于动画的原生支持—defer transitions.

先看看svelte所谓的defer transition的效果吧。

如何在Vue中实现Svelte的Defer Transition

这是使用svelte做的todo demo应用。整个todo分成3个部分。输入部分,todo列表和done列表。当点击todo列表中的条目时,相应条目会被“移动”到done列表,反之亦然。

在这里,条目从一个列表转移到另一个列表,不是很突兀的闪现,而是非常友好地从点击处,移动到目的地;同时,当列表中条目离开时,剩余的条目会丝滑地向上移动填补空缺的位置。在svelte里,只需要仅仅加上几行代码,就能实现,对于开发者非常友好且高效。 参考如下代码或者svelte教程

仅仅在element上加上了in、out和animate属性。这里,in和out各自接受框架提供的函数receive和send并且给他们提供了筛选条件。 animate属性接收内置的flip方法。这里的flip不是翻转,而是flip技术技术,vue在<transition-group>中也有用到。主要用于整体移动列表剩余条目去填补所失去元素的位置。

于是我就在想,如果是vue的话,如何能达到相应的效果呢。 (不想看详细说明的话,可以直接查看code pen中的代码)

vue原生提供了两个组件支持动画。transition和transition-group。由于是list的移动,所以我们这里使用transition-group。具体使用方法可以参考vue教程transitions & animation

要想达到同样的效果,有两大ui动画效果要实现。

列表中条目消失时,剩余条目移动补齐空位
条目消失同时在另外一个列表插入时,条目移动
第一个需求的实现比较简单,vue原生已经提供了良好的支持,参考vue文档中的list-move-transitions即可

为了实现第二个需求,有几个问题必须解决:

  1. 消失条目的位置信息
  2. 插入条目的位置信息
  3. 动效开始与结束的时机

我们先看看前两个问题的如何解决。根据文档的介绍,transition-group提供了javascript hook。分别是:

可视化表示的话,大概是如下图所示:

如何在Vue中实现Svelte的Defer Transition

before-enter: 用于设置插入条目的transition的初始值。此时无法获取boundingclientrect. enter: 动效期。此时enter钩子函数的入参el能获取boundingclientrect after-enter: 动效结束后的回调函数 enter-cancelled: 取消enter的钩子

leave也是类似。

所以,我们能拿到条目元素domrect信息的时机只有enter和leave的时候。

这样,我们就可以在leave时候,拿到leave条目的domrect数据并且保存起来。在enter的时候, 我们就能同时拥有leave条目和enter条目的位置信息了。

位置信息是拿到了,那怎么才能在条目进入的时候,有从消失条目移动过来的效果呢。(可以先想想, 再看后面的解释)。

所以,我们想要达成移动的效果,首先需要隐藏掉leave条目元素,

然后给enter条目元素设定关于位置初始状态,初始化的位置即为leave条目元素的位置,然后当transition开始生效的时候,让其位置恢复到插入(enter)的位置。

这种方法其实就是所谓的flip技术。transition-group组件里也使用了这种技术来移动剩余列表填充移走条目空白。

那么接下来的问题就是,在什么时机去设置enter条目元素transition的初始状态,在什么时机去设置enter条目元素transition的结束时状态。

按照上面提到的javascript hook,我们可以在before-enter钩子函数里设置初始状态,接着在enter钩子函数里设置transition结束状态。那么,我们的初始状态是什么呢?我们通过getboundingclientrect,可以获取到enter元素(后用to来标识)的domrect数据,包括top, left, bottom, right, width, height , x, y。 同时我们也能通过之前保存的leave位置map获取到leave条目的位置信息(称为from)。所以在before-enter时,我们通过计算得到的偏移量,通过translate去初始化to元素的位置。然后再在enter阶段,translate其值到from, 再加上transition到css中即可。

在before-enter钩子中:

在enter钩子中:

上面的代码中,在before-enter里面,to是通过receiverectmap.get(key)来获取的。但是,这时,receiverectmap中还没有对应key的domrect值。虽然,before-enter的入参是el(htmlelement),但是该el元素的domrect中的所有值都为0,所以我们需要在enter方法中,把el塞入到receiverectmap中。这样就会有一个矛盾,那就是无法在before-enter中通过translate初始化to元素的位置了。所以,我们这里使用defer transition技术,延迟transition的发生。

我们可以在enter中使用settimeout或者requestanimationframe实现defer transition,

完整代码可以参考codepen

最后效果:

如何在Vue中实现Svelte的Defer Transition

以上就是如何在vue中实现svelte的defer transition的详细内容,更多关于vue 实现svelte的defer transition的资料请关注其它相关文章!