Svelte列表crossfade动画随机错位问题排查与解决
列表项选中动画问题及优化过程
我想要实现这样的列表动画效果:选中列表项时,该项滑动到顶部,其余项飞出;再次选中时,该项回到原位置,其余项飞回。参考crossfade示例完成了一个实现,但测试发现元素有时无法回到初始位置,只有再次触发动画才可能修复。确定是crossfade函数需要优化,或者应该改用常规transition,但不知道具体怎么操作。
初始实现代码
<script> import { flip } from 'svelte/animate' import { writable } from 'svelte/store' import { crossfade, fly } from 'svelte/transition' const ACTIONS = [ { key: 'blue' }, { key: 'green' }, { key: 'yellow' }, { key: 'purple' }, { key: 'orange' }, { key: 'red' }, ] const selectedAction = writable(null) let shownActions = ACTIONS.map(a => a) const [send, receive] = crossfade({ fallback(node, _params) { return fly(node, { x: -800, duration: 600 }) } }) function selectAction(action) { if ($selectedAction === action) { shownActions = ACTIONS.map(a => a) selectedAction.update(v => { if (v === action || action === undefined) { return null } else { return action } }) } else { shownActions = ACTIONS.filter(a => a.key === action) selectedAction.update(v => { if (v === action || action === undefined) { return null } else { return action } }) window.scrollTo({ top: 0, behavior: 'smooth' }) } } </script> <ul> {#each shownActions as action (action)} <li class={`${$$props.class || ''}`} animate:flip={{ duration: 600 }} in:receive={{ key: action.key }} out:send={{ key: action.key }} > <button on:click={e => selectAction(action.key)}>{action.key}</button> </li> {/each} </ul> <style lang="scss"> ul { list-style: none; } li { display: flex; margin-bottom: 1rem; } button { margin-right: 1rem; padding: 0.5rem 1rem; } </style>
编辑说明
最终我移除了列表飞出动画,仅保留单个项的滑动效果,视觉上更简洁。升级Svelte版本后,动画问题有所缓解——此前存在动画元素未正确重置导致挤压的情况。
所有项的进出动画代码
{#each shownActions as action (action)} <li class={`${$$props.class || ''}`} animate:flip={{ duration: 500 }} in:fly={{ delay: 0, duration: 500 }} > <div class={`${$$props.class || ''}`} in:receive={{ key: action.key }} out:send={{ key: action.key }} > <button on:click={e => selectAction(action.key)}>{action.key}</button> </div> </li> {/each}
偏好的无其余项飞出动画代码
{#each shownActions as action (action)} <li class={`${$$props.class || ''}`} animate:flip={{ duration: 500 }} in:receive={{ key: action.key }} > <button on:click={e => selectAction(action.key)}>{action.key}</button> </li> {/each}
内容的提问来源于stack exchange,提问作者TeemuK
相关产品推荐
相关产品推荐

