图片的异步加载

spritejs支持图片URL作为资源,我们前面已经看过,我们可以把URL作为texture直接传给Sprite的textures属性。但是,因为网络图片资源是异步加载的,这会可能导致sprite的异步显示以及我们拿到的sprite的contentSize为0。

预加载与雪碧图 - 图1

获取图片大小之所以为0,是因为当我们把label添加到layer上的时候,图片还没有完成加载,因此此时的sprite里没有内容来撑开宽高,所以得到的大小就是0。

  1. const scene = new Scene('#load-texture', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const robot = new Sprite('https://p5.ssl.qhimg.com/t01c33383c0e168c3c4.png');
  4. robot.attr({
  5. anchor: [0.5, 0.5],
  6. pos: [770, 300],
  7. scale: 0.5,
  8. });
  9. layer.append(robot);
  10. const label = new Label(`图片大小: ${robot.contentSize}`);
  11. label.attr({
  12. anchor: [0.5, 0.5],
  13. pos: [770, 100],
  14. font: '36px Arial',
  15. });
  16. layer.append(label);

scene提供了preload方法来预加载和保存图片资源。这个方法可以接受一个或多个图片数据,返回一个promise对象。

预加载与雪碧图 - 图2

我们通过preload事先预加载并缓存了图片,所以我们使用id:'robot'来创建sprite时,就可以立即显示出来,并得到contentSize。

  1. ;(async function () {
  2. const scene = new Scene('#preload-texture', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  3. await scene.preload({
  4. id: 'robot',
  5. src: 'https://p5.ssl.qhimg.com/t01c33383c0e168c3c4.png',
  6. });
  7. const layer = scene.layer();
  8. const robot = new Sprite('robot');
  9. robot.attr({
  10. anchor: [0.5, 0.5],
  11. pos: [770, 300],
  12. scale: 0.5,
  13. });
  14. layer.append(robot);
  15. const label = new Label(`图片大小: ${robot.contentSize}`);
  16. label.attr({
  17. anchor: [0.5, 0.5],
  18. pos: [770, 100],
  19. font: '36px Arial',
  20. });
  21. layer.append(label);
  22. }())

雪碧图

与css雪碧图一样,spritejs也支持雪碧图。spritejs支持texture packer生成的标准JSON雪碧图。

预加载与雪碧图 - 图3

使用雪碧图可以有效减少HTTP请求,从而提高响应速度。

  1. ;(async function () {
  2. const scene = new Scene('#texturepacker', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  3. const earthPNG = 'https://p3.ssl.qhimg.com/t01806718065fe97c65.png',
  4. earthJSON = 'https://s3.ssl.qhres.com/static/d479c28f553c6cff.json';
  5. await scene.preload([earthPNG, earthJSON]);
  6. const layer = scene.layer();
  7. const group = new Group();
  8. group.attr({
  9. pos: [655, 215],
  10. });
  11. const earth = new Sprite();
  12. earth.attr({
  13. textures: 'earth_blue.png',
  14. pos: [115, 115],
  15. anchor: [0.5, 0.5],
  16. });
  17. const earthShadow = new Sprite();
  18. earthShadow.attr({
  19. textures: 'earth_shadow2.png',
  20. pos: [0, 0],
  21. });
  22. group.append(earth, earthShadow);
  23. layer.append(group);
  24. earth.animate([
  25. {rotate: 0, textures: 'earth_blue.png'},
  26. {rotate: 360, textures: 'earth_yellow.png'},
  27. {rotate: 720, textures: 'earth_green.png'},
  28. {rotate: 1080, textures: 'earth_white.png'},
  29. {rotate: 1440, textures: 'earth_blue.png'},
  30. ], {
  31. duration: 20000,
  32. iterations: Infinity,
  33. });
  34. }())

批量资源预加载进度

有时候,我们要预加载大量的资源,此时我们可以在preload的时候显示一个进度。

预加载与雪碧图 - 图4

我们可以监听scene的preload事件来获取资源加载的进度,因为例子里这些图片不大,所以加载还是很快,可能需要打开控制台,模拟慢速网络才能看到效果。

  1. const scene = new Scene('#preload-many', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const images = [
  4. 'https://p1.ssl.qhimg.com/t016dc86e4b2c9b83a4.jpg',
  5. 'https://p0.ssl.qhimg.com/t01408bb4e2bed11d2e.jpg',
  6. 'https://p2.ssl.qhimg.com/t014e6d3eddccf40638.jpg',
  7. 'https://p2.ssl.qhimg.com/t014db3a8e2bf146c5b.jpg',
  8. 'https://p4.ssl.qhimg.com/t01ff1bf2a37a741821.jpg',
  9. 'https://p2.ssl.qhimg.com/t01dc1341ab5d0fe663.jpg',
  10. 'https://p5.ssl.qhimg.com/t01a0acf6aa37d00f91.jpg',
  11. 'https://p1.ssl.qhimg.com/t013b8514570a69a1c8.jpg',
  12. 'https://p2.ssl.qhimg.com/t011c71494e6d98d92b.jpg',
  13. 'https://p4.ssl.qhimg.com/t01ab40609e924d995c.jpg',
  14. 'https://p0.ssl.qhimg.com/t01794495bebb84f47d.jpg',
  15. 'https://p4.ssl.qhimg.com/t01a30bb66a9d11d624.jpg',
  16. 'https://p4.ssl.qhimg.com/t01b3d2c0b0093a957d.jpg',
  17. 'https://p0.ssl.qhimg.com/t010da5e7311c8dd3a9.jpg',
  18. 'https://p5.ssl.qhimg.com/t0189dd547c322b2357.jpg',
  19. 'https://p4.ssl.qhimg.com/t01feb50457ebbada10.jpg',
  20. ];
  21. const label = new Label('加载中... 0 / 16');
  22. label.attr({
  23. anchor: [0.5, 0.5],
  24. font: '36px Arial',
  25. pos: [770, 200],
  26. });
  27. layer.append(label);
  28. const button = new Label('点击加载');
  29. button.attr({
  30. anchor: [0.5, 0.5],
  31. font: '44px Arial',
  32. pos: [770, 350],
  33. border: [2, 'black'],
  34. borderRadius: 12,
  35. padding: [10, 10],
  36. });
  37. layer.append(button);
  38. async function loadRes() {
  39. button.remove();
  40. scene.on('preload', (evt) => {
  41. label.text = `加载中... ${evt.loaded.length} / ${evt.resources.length}`;
  42. });
  43. const imgs = await scene.preload(...images);
  44. label.remove();
  45. imgs.forEach(({texture}, i) => {
  46. const sprite = new Sprite();
  47. sprite.attr({
  48. textures: [texture],
  49. x: 125 + (i % 8) * 170,
  50. y: 100 + Math.floor(i / 8) * 200,
  51. size: [150, 150],
  52. });
  53. layer.append(sprite);
  54. });
  55. }
  56. button.on('mouseenter', (evt) => {
  57. scene.container.style.cursor = 'pointer';
  58. });
  59. button.on('mouseleave', (evt) => {
  60. scene.container.style.cursor = 'default';
  61. });
  62. button.on('mousedown', (evt) => {
  63. evt.target.attr('scale', 0.8);
  64. });
  65. button.on('mouseup', (evt) => {
  66. evt.target.attr('scale', 1);
  67. loadRes();
  68. });