作者:王鑫哲
在页面上绘制canvas/webgl动画必须保证所需的序列帧顺利加载。最常见的做法是手动或者用loader把这些图片一张张从cdn加载进来,或者拼成精灵图,加载后手动分离序列帧。但是,单独加载会大幅增加http请求,某些api还要求同源策略,拼成精灵图又有图片过大风险。趁此机会,今天就向大家介绍几种不常见的,自己在项目中有到过的大批量图片加载方式。
利用Pixijs或Threejs制作视觉效果绚丽的h5宣传页越来越流行。哈利波特20周年、UP2017年会等案例均有很好的传播效果。精美视觉效果意味着需要增加大量图片资源,而大批量图片加载一直是web页面优化中绕不过的点。无论是制作webgl/canvas动画,还是直接css轮播图片,开发人员都需要将设计师给的每一帧图片插入到页面,保证全部加载后再播放动画。
保证所需的大量图片顺利加载,最传统的做法是手动或者用动画引擎自带的loader把这些图片一张张从cdn load进来,或者拼成精灵图,加载后一张张分离。但是,单独加载会产生大量http请求,并要求cdn图片开启跨域支持,而拼成精灵图又有图片过大风险,导致低端移动设备闪退。
趁此机会,今天就向大家介绍几种不常见的,我在项目中用到过的大批量图片加载方式。
得益于现代浏览器的Typed Array,bloburl,以及前人的努力,目前浏览器环境可以轻松下载二进制文件并在页面里解压得到里面的单个图片。只需用压缩软件将图片资源统一打包成zip格式,线上页面加载时请求这个zip文件,本地解压即可得到图片blob对象。
把图片打包到zip里面无非是为了减少http请求,减少回调函数和代码复杂度,保证请求一次即可使用资源,而不必担忧单个图片加载出错的问题。按照这个思路,其实可以把序列帧按转成base64,按播放先后顺序放到json文件里。线上请求json文件,把base64填入image的src中得到序列帧。
就像这样:
$.ajax({
url:'/sprites.json',
dataType:'json',
success:function(base64Ls){
var imageLs = base64Ls.map(function(v){
var img = new Image();
img.src = v;
return img;
});
createSpriteAnimation(imageLs);
}
});
性能:
跨域问题:可以用jsonp解决
目前这个页面的动画资源就是用这种方法加载的,因为是直接绘制到canvas,所以也不处理dataurl跨域问题
如果仅仅加载大量图片,那么方法2是最简单的,但是会有各种跨域问题,所以又有方法3,图片转base64存js文件,取出后赋值src得到可用的image。用jsonp解决了跨域。于是变成下面这个样子: 资源:
jsonpCallback(['data:image/png;base64,各种地址1','data:image/png;base64,各种地址2','data:image/png;base64,各种地址2']);
获取:
$.ajax({
url:'https://cdn.com/jsonp.js',
dataType:'jsonp',
callback:'jsonpCallback',
success:function(base64Ls){
var imageLs = base64Ls.map(function(v){
var img = new Image();
img.src = v;
return img;
});
createSpriteAnimation(imageLs);
}
});
与方法二一样
对于web页面动画大量图片资源的加载,可以用这些方法:
三种图片加载方式各有优缺点,需要根据应用场合选择。方法二代码量和逻辑都很简单,如果只是简单地将序列帧图片绘制到canvas上,方法二非常合适。当项目中使用了webgl,图片不能跨域,而且有其他资源也想打包,那么推荐方法一,打包成zip,在线解包。 要是没办法把zip文件放到域名下,又没办法添加cors头部,那么就使用方法三吧,因为方法三没在实际中使用过,效果未知,在此不敢保证。
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者王鑫哲授权发布。