如安在Vue中实现Svelte的Defer Transition

最近寓目了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教程

{#each todos.filter(t => !t.done) as todo (todo.id)} <label in:receive="{{key: todo.id}}" out:send="{{key: todo.id}}" animate:flip> <input type=checkbox on:change={() => mark(todo, true)}> {todo.description} <button on:click="{() => remove(todo)}">remove</button> </label> {/each}

仅仅在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文档中的即可

为了实现第二个需求,有几个问题必需办理:

消失条目标位置信息

插入条目标位置信息

动效开始与竣事的机缘

我们先看看前两个问题的如何办理。按照文档的先容,transition-group提供了javascript hook。别离是:

v-on:before-enter v-on:enter v-on:after-enter v-on:enter-cancelled v-on:before-leave v-on:leave v-on:after-leave v-on:leave-cancelled

可视化暗示的话,或许是如下图所示:

如何在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条目元素,

leave(el, done) { console.log("before leave"); const rect = el.getBoundingClientRect(); sendRectMap.set(el.dataset.key, rect); el.style.display = "none"; },

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

这种要领其实就是所谓的FLIP技能。transition-group组件里也利用了这种技能来移动剩余列表填充移走条目空缺。

var first = el.getBoundingClientRect(); // Now set the element to the last position. el.classList.add('totes-at-the-end'); // Read again. This forces a sync // layout, so be careful. var last = el.getBoundingClientRect(); // You can do this for other computed // styles as well, if needed. Just be // sure to stick to compositor-only // props like transform and opacity // where possible. var invert = first.top - last.top; // Invert. el.style.transform = `translateY(${invert}px)`; // Wait for the next frame so we // know all the style changes have // taken hold. requestAnimationFrame(function() { // Switch on animations. el.classList.add('animate-on-transforms'); // GO GO GOOOOOO! el.style.transform = ''; });

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsjfgs.html