五一在家,看了之前 Anthony Fu 的直播录播,内容是制作一个跨路由的共享元素的动画的组件库,大致听了一下思路,了解了其原理,自己便尝试利用他后来发布的这个组件库做了一个动画效果。
最早,Fu 分享的是 FLIP 的思路。FLIP 大致是把元送从最终位置移动到初始位置,由于还没有发生渲染,用户是不知道元素已经到达最终位置了,然后再利用动画将元素播放到最终位置。
这就是 FLIP 的大致原理,具体的可以留到下次手撸一个 FLIP 动画效果后再分享。
这个方案对于简单元素的效果,还是能够接受的,但是如果对于整个组件做这种 FLIP 动画,由于其实是两个组件,它们的状态是不能直接共享的,当然你可以使用状态管理解决,但是为了一个动画效果,这太“重”了。
Fu 的思路是将整个组件使用 Vue3 的 Teleport,把组件从组件树上挪动,像是星际争霸游戏里人族建筑可以从地上飞起现浮动在天上,再移动到目标位置下降的过程,非常形象生动。
虽然,这是一个 Vue 的库,应用到其他框架里,从原理上看也是没有问题的。
我发现组件状态虽然能够共享了,但是你如果注意到我的截图后,你会发现组件的动画又重新开始播放了,这是由于我用的 CSS 做的动画,组件在 dom 中移动后导致动画重新开始。
这就意味着,我至少需要额外的工作去记录一下动画播放的位置,下次重新播放是需要从这个位置开始,同样也会新增一点复杂性。我这一次不打算优化了。
可以说这个动画效果已经非常接近原生了,这种动画效果 Flutter 里和 Swift 里都有同一个称呼 Hero,Flutter 里是官方支持的原生组件,Swift 里则是第三方库。
在之前做原生开发时,就觉得效果非常的神奇,但是原理基本不知道。没想动 Web 里,同样能够实现这种效果,相信 Web 开发的应用体验会越来越好。
v-bind(x)
绑定变量,之前知道这个功能没有试过,这次应用这个来控制动画需要移动的位置。