基于canvas的网站开发总结

阿凡达2018-08-01 12:53

需求&选型

前期接到需求的时候,是想做一个强动画的页面,效果参考这个页面。很明显这是一个canvas绘制出来的、带用户交互的页面。

虽然以前没有做过类似这样的页面,不过跟canvas相关的内容还是做过不少,不难想象要想用canvas做一个这样的页面出来,大致需要以下几个方面的内容:

  1. canvas2D渲染库
  2. js动画库
  3. AnimateCC(动画师)

canvas2D渲染库

目前市面上有很多2D的canvas库,大多数是用来做游戏的,基本没有提及适用于我们目前的这种需求场景的。看了几个不同的库之后,发现渲染库的原理基本都差不多,都是定义了许多自己的类,从而对不同的实例进行控制从而实现动画和交互。

初步比较之后,选择了easeljsPIXI.js,来做同一个demo,对比了性能之后,因为easeljs在低端安卓机上的性能问题果断选择了性能较好的PIXI.js作为canvas渲染库。

js动画库

有了canvas渲染库之后,还需要控制元素动画流程和衔接的动画库。GSAP中有单个动画和Timeline的概念,不仅能对单个元素的动画进行控制,还能定义一整串的动画流程,从而时间动画的穿插、串联等一系列复杂的操作。

AnimateCC

AnimateCC是动画师做动画用的软件,它本身内置了导出为Canvas文档的功能,这样理想情况下,页面中有动画的部分都能动画师来做,前端只需要用js在不同交互种类发生的时候来衔接不同页面就行了,但是既然提到了js动画库,说明实际使用中,这种理想情况是不存在的,后面动画部分详细说。

另外,还有一个第三方开发的插件,pixi-animte,能使animateCC直接导出为用PIXI.js的API包装过的代码,直接用PIXI的api就能操作动画元素。

开发

针对这一套技术方案的canvas页面,在开发过程中也主要有三个方面的内容:AnimateCC、动画和页面逻辑。这三个部分的关系如下:

AnimateCC

前面说过,在pixi-animate插件的加持下,animateCC可以直接将文稿导出为PIXI.js包装过的元件,可以直接调用PIXI相关API来对元件进行操作。

因为在canvas中渲染跟传统的css布局有本质的区别,因此页面的布局都是在AnimateCC中完成的

可以看做是传统的html元素被PIXI的MovieClip代替了,每个MovieClip就代表一个html元素,可以包含子元素,可以通过js来调用PIXI相关的API,包括位置等属性。这样,不仅可以通过PIXI来播放AnimateCC中定义的元素本身的帧动画,还可以通过GSAP来控制元素的位置实现位移、变形等外部的动画。

动画

关于动画这部分,前面提到过,理想情况下实际上是不需要前端来引入动画库然后去控制元素的属性去实现动画的,而是动画师在AnimateCC这一步就将动画做好一并导出,前端拿到导出的js通过使用PIXI的API来实现动画的控制和播放。

但是,but,however,这样做有几个不太现实的点

  1. 动画师是做一些特效视频动画的,页面元素动画太多太繁琐,动画师没有这么多工时。
  2. 就算动画师有足够的时间完成所有的页面元素类动画,动画师也需要将动画的接口文档写的非常详细,才能在前端调用动画的时候不会一脸懵逼。
  3. 如果页面是需要后期维护和修改的,一旦有个页面需要修改或者微调,涉及的就是前端和动画师两个工作量了。

综上,放弃了动画师在AnimateCC中做页面元素动画的方案,改为前端包干。在AnimateCC中将某个页面的初始状态布局好之后,导出为PIXI元件,然后通过GSAP来在特定时候操作元件进行动画。

页面逻辑

有了页面和动画之后,还需要能够控制页面加载、初始化、切换等一系列操作的逻辑。

PIXI中有自带的load可以用来加载资源,文档里也清楚的写了初始化的方法,但是如果一股脑的将所有页面加载到内存的话,在低端机中会卡死然后崩溃。所以这里的工作主要是怎么保证页面单独加载而又不会影响canvas切换页面的连贯性。

这里的方法是将页面分成几个部分,例如首页、内页1、内页2。每一个部分都由一个根MovieClip元件包裹,也就是每个部分都是一个单独的PIXI应用,互不关联。在页面切换的时候只需要在过渡中加一个连贯的加载页面,就能在销毁上一个页面之后再初始化下一个页面的同时不影响连贯性,并且内存占用也不会过高。

总结

一边摸索一边用这套技术方案做出来的项目最终也上线了(逆水寒移动官网),最终的效果可以接受,不过过程中确实有许多的坑,和一些值得思考的地方。

优点&缺点

这套canvas技术方案相较于传统的html+css+js的方案有优点也有缺点

优点

  1. 移动端适配不用操心,只要能支持html5-canvas的浏览器渲染出来的页面就是一样的,只需要处理一下屏幕大小的适配,不像css3的各种特性的兼容性都不太一致。

缺点

  1. 开发流程复杂。前端需要先在AnimateCC中布局相关页面,然后再导出为js,如果页面需要后期的维护和更新,就会存在AnimateCC和js编辑器两部分工作量。
  2. 难以调适样式。由于样式布局都是在AnimateCC中用图形化界面完成的,在浏览器中是不能像传统html+css页面那样看每个元素的样式信息的。
  3. 动态布局工作量大。举个很简单的例子,在页面中,我们需要从后台拉取一个图片数组并将图片插入到页面中。在传统的页面中,我们只需定义好外层css然后插入图片,图片会按照我们定义的方式布局。但是在canvas中,没有了css布局,所有的布局都由js完成,我们需要动态计算每次要插入的位置并一个一个插入到canvas的相应位置中。
  4. 布局不能动态适配不同屏幕。由于页面元素是事先在AnimateCC的固定尺寸的canvas中摆放好了的,所以在不同屏幕大小的环境下并不能像传统css布局可以通过一些技巧动态自适应。要想canvas在不被拉伸变形,只能将多余部分留白。

适用场景

如果没有上门的诸多缺点,单从效果来说的话,canvas渲染还是挺有优势的,尤其是在低端安卓机中css兼容性不容乐观的情况下,又想要做到动画表现的一致性和流畅性。所以如果一个项目能满足以下几点特性,用这一套技术方案也未尝不可:

  1. 一次性项目,后期不需要维护和修改。
  2. 静态项目,没有大量的动态数据需要渲染。
  3. 项目UI简洁,方便做自适应。

如果回头看文章开始给的那个例子,可以发现它就满足了上面几个特点,所以看起来毫无违和感。

替代方案

因为当初动画师做AnimateCC动画前端直接拿来用的美好愿景被打破,如果再让我做一次类似逆水寒移动官网这种不满足以上特点的项目,我会去掉canvas,就用一个GSAP做动画库,用js控制页面元素进行动画。这样开发起来对于前端来说更加直观,并且在动画这部分的工作量基本跟用canvas持平。

这样可以省去后期维护修改的AnimateCC那部分的时间成本。在js控制css动画方面稍微注意一下性能优化在低端安卓上进行动画也不会有太大的问题。同时有GSAP对于动画流程控制上的便利性,传统页面的元素动画也能得到流畅性的保障。最后达到的效果也不会输canvas。

参考文献

本文来自网易实践者社区,经作者查马纠西授权发布。