因为现在项目做的东西都是小游戏,游戏和普通web应用有一个很重要的环节就是预加载,在游戏开始之前必须把所有图片等静态资源都加载到本地,等到游戏中真正要用到资源的时候可以直接从缓存中拿,而不是用到的时候再去后端拿,达到优化游戏体验的目的。
但是最近用vue开发小游戏的时候遇到了一个很坑爹的问题,就是原来的那一套预加载方式不生效,loading页面已经加载过一遍的图片在游戏中真正用到的时候还会再请求。所以针对这个问题,和别人讨论和写demo重现尝试过后发现了问题所在和想了一套解决方案。写下记录,防止以后忘记。
原来的写法
原来有问题的写法是参照旧时普通单页面游戏的写法,所有游戏都在同一个路径下,由js控制显示不同div来实现页面切换,本质上就是一个页面。所以
new Image().src = '//24haowan.com/preload.png'
这种写法,图片是会缓存在当前页面。
而这种写法在用vue搭建的项目里就不太好用了。切换到其他组建之后,预加载的图片已经找不到了,浏览器还是会向后台发起请求。尽管第二次服务器返回的是304
,但是还是会有延迟,达不到图片秒加载的效果。
最终,写demo重现了以上问题,总结出了以下规律:
在组建A中使用new Image().src = 'resource'
的方式加载图片,组建B中使用<img :src="require('resource')">
的方式加载图片,然后
- 从组建A跳转到组建B,会加载两次图片
- 从组建B跳转到组建A,只会加载一次图片
所以可以初步得出结论:
使用new Image().src = 'resource'
方式加载图片不会被缓存。我简单猜测,在组建A中加载的图片没有被插入到html中,图片缓存始终是在js里,而组建切换之后,组建A销毁了js代码,导致缓存的图片被清理掉。
解决办法
解决办法本质上就是不让预加载的图片被清理掉。
把预加载的图片存到全局变量
和phaser的思路一样,把new Image()
得到的dom对象都存在一个对象中,在真正用到的时候,把需要的图片dom对象插入到合适的地方。
优点:真正的复用对象,理论性能最高
缺点:
- 好像vue的v-html方法不能直接插入一个dom对象。
- 如果把图片放到背景里怎么操作?
把预加载的图片插入到html里。
把所有的图片路径放入一个数组,v-for一遍都插入html里。
用一个img标签循环加载图片资源
用一个隐藏的img标签,循环加载图片资源路径,缺点是难以实现多张图片异步加载。