设计稿生成代码( imgcook )居然还可以开发动画 !

avatar
阿里巴巴 前端委员会智能化小组 @阿里巴巴

文/ 阿里淘系 F(x) Team - 雷姆

imgcook 是阿里巴巴旗下的软件即服务产品。它可以通过智能化技术把不同种类的视觉稿(Sketch/PSD/静态图片)一键生成前端代码。 一般来说,使用 imgcook 都是用来做一些静态的模块,但随着我们淘宝设计向沉浸式迈入,对于 imgcook 来说就不得不也进行一些动效的开发。 ​

动效分解

比如氛围滚动、比如 Feeds 商品的动效切换,比如最近我就在一个模块里开发了一个动效如下:


首先来分解动画, ​

  1. 将原商品图以左上角为基准缩小,同时将状态一的其他部分隐藏
  2. 等待1完成后
    1. “可能喜欢”渐变显示出来
    2. 右侧的推荐商品向左滑动
  3. 完成

分解完毕后,是比较简单的,但是实际通过 imgcook 开发时,还是经历了不少学习的过程。 ​

动效实现

首先,对于第一个步骤,切分状态,那么这里我们先创建状态,如下:



为了保证商品图平滑的过渡,需要保证两个商品图(Picture)是一个节点,接下来就可以开始第一阶段。


我们通过 state.recommend 来表示不同的状态,然后通过 imgcook 状态表达式来改变图片的宽高,并且通过设置 transition 属性来设置动效参数,隐藏其他组件就比较简单,直接通过 imgcook 设置是否渲染即可。 ​

接下来就是等待阶段1完成后,显示“可能喜欢”,这一部的难点在于如何设置延时时间,我们可以通过设置 transitionDelay 来完成:


上述的代表表示渐变动效执行 0.3s,延时 0.6s 执行,因为之前我们设置阶段一的过渡时间是 0.6s。再接下来就是改变组件的透明度,这里我们使用了 View 组件的 onAppear 事件来完成。


通过增加 _参数,来获取元素(_event参数,来获取DOM元素(event.target),然后在函数里配置:

target.style.opacity = 1;

当然还有一种写法是:

this.set({ recommendOpacity: 1 });

由于前者比较简单,所以我选择了直接操作 DOM 元素。 ​

接下来就到了最后的一个动画,从实现来说,也能通过 transition 完成,但是这里为了讲解如何使用 imgcook 开发更为复杂的动效,我使用了 keyframes 来实现。 ​

在开始思考之前,我们就遇到一个问题——如何在 imgcook 直接增加 CSS 样式呢?因为 keyframes 需要定义在 CSS 或 style 标签中,在这个过程中,我想过很多黑科技,比如使用 Rax 的 rax-keyframes-to-animation,以及在模块中动态的增加 style 标签来添加。 ​

这些方案都不是太好,第一个方案会依赖于 Rax 生态,无法复制到其他框架,第二个方案虽然可以,但实在是不优雅,直到最后,我发现了 Element.prototype.animate,它是一项 Web 实验性功能,跟 keyframes 其实是对等的一套 Web API,在每个 DOM 元素对象上,可以通过 animate 方法,将 keyframes 所需的配置设置进行,从而实现与 keyframes 和 CSS animation 等价的功能。 ​

首先呢,还是通过 onAppear 事件,获取到右侧的元素:


然后在函数里如下使用:

const keyframes = [
  { transform: `translate3d(100%, 0, 0)` }, // from
  { transform: `translate3d(0, 0, 0)` } // to
];
target.animate(keyframes, {
  delay: 600,   // 延时600ms
  duration: 1000, // 设置过渡时间   
  easing: 'ease',   // 设置过渡函数   
  fill: 'forwards', // 设置动画结束后保持最后一帧的样式 
}); 

除此之外,我们还需要保证元素的默认样式与 keyframes 的第一帧保持一致,所以需要设置:


这样,整个动画效果就完整地实现了,不过其实现在的实现还遗留了一个 Bug,因为我们是使用 onAppear 来触发动效的,所以当元素从屏幕划过再出现时(比如 Feeds 向下滚动再回滚),会再次触发动效,因此我们还需要对我们的实现稍作改进。 ​

定义一个 animStarted,初始状态为 false 或 undefined,在函数内判断 animStarted 是否为 true,如果为 true 代表动效执行过了,就直接 return 出去,否则调用 animate() 开始执行,执行完毕后,设置 animStarted 为 true,这样我们就规避掉了 onAppear 重复执行的问题了。 ​

总结与建议

通过本文的描述,我坚信可以使用 imgcook 覆盖绝大部分电商场景下(除了游戏外)的动效了,简单的动效使用 transition 和 transitionDelay 组合,稍微复杂的帧动画可以通过 animate 来实现。 ​

不过对于 imgcook 来说,也不是说非常完美,这里提2点建议,可以辅助我们更好地开发动效:

  1. 支持 once 的事件绑定,这样开发者就不必再通过一个额外的状态来实现了单次动效了
  2. 支持动效在画布上预览,这样就无需每次出码后才能调试了

最后,欢迎大家使用 imgcook 全新的基于函数的开发方式来写前端,这样我们可以把省掉的脑力去想一些更有意思的事情,同时也可能写出更少的 Bug。



淘系前端-F-x-Team 开通微博 啦!(微博登录后可见)
除文章外还有更多的团队内容等你解锁🔓