前言
正所谓金三银四五吃土,因此这些天几个前端技术群讨论最多的话题就是面试题了。某日群内讨论一道面试题:“前端如何实现大量图片预加载以及预加载进度动画进度条显示?”
恰巧本人以前jquery、zepto一把梭快乐切图的时候,写过不少形式的图片预加载动画。对于图片预加载的原理稍微了解接触过那么一点点,这里献丑一番简单写一个预加载案例,作为19年第一篇博(段)客(子)快乐一哈。
一、利用image对象搞事情
既然是利用image对象搞事情,那肯定少不了大量的img图片。因此我从名字中包含刺激二字的网站上面扒了不少各位带妹司机热血沸腾的图片,没错就是腾讯刺激战场--各种武器图片。
emmm,不皮了。我们直接进入主题内容,JavaScript当中的image对象。关于Image对象的介绍MDN上面写的, 当new Image()
的时候会生成一个HTMLImageElement
.
HTMLImageElement
这是什么?和我们熟悉的HTMLElement
这个节点有什么不同呢?顺着上面的链接提示,我们继续顺藤摸瓜,最后发现HTMLImageElement
属于HTMLElement
孩子。
既然继承了HTMLElement
特性,同理body元素有一个onload
属性,那么同理new Image得到对象也同样拥有onload
属性。
那么就让我们利用,new Image()
来搞事情
二、预加载和预加载动画实现
1、批量设置图片路径
平常我们在接触img
元素的时候,都知道书写img
标签的时候,必然少不了添加src
属性,不然图片加载不出来。所以我们第一步就是批量设置这些需要预加载的图片路径地址,这样onload
才能发挥其作用。
这里的图片太多了,一张一张的手写,未免太麻烦了。为了节省时间,这里我拿出一年多以前刚刚学Node的时候写的一个js脚本,来批量获取图片名称生成数组对象列表。
PS:这里就不挂载nodefs脚本代码,文末我将会这个小demo地址附上(包括nodefs.js
),感兴趣的小伙伴可以点击访问。
2、预加载图片效果测试
因为我此前是用的webpack工具构建的项目,支持模块引入imglist.js
. 这里我为了demo演示,因此我们就直接将这个数组对象复制粘贴到演示HTML当中。
<body>
<h1 class="loading"></h1>
</body>
</html>
<script>
let imglist = [{name: 'AKM', url: 'AKM.png'},{name: 'AUG', url: 'AUG.png'},{name: 'AWM', url: 'AWM.png'},{name: 'crossbow', url: 'crossbow.png'},{name: 'Crowbar', url: 'Crowbar.png'},{name: 'DP-28', url: 'DP-28.png'},{name: 'G36C', url: 'G36C.png'},{name: 'Groza', url: 'Groza.png'},{name: 'Kar98k', url: 'Kar98k.png'},{name: 'M16A4', url: 'M16A4.png'},{name: 'M24', url: 'M24.png'},{name: 'M249', url: 'M249.png'},{name: 'M416', url: 'M416.png'},{name: 'M762', url: 'M762.png'},{name: 'Machete', url: 'Machete.png'},{name: 'Micro-UZI', url: 'Micro-UZI.png'},{name: 'Mini14', url: 'Mini14.png'},{name: 'Mk14', url: 'Mk14.png'},{name: 'MK47', url: 'MK47.png'},{name: 'P18C', url: 'P18C.png'},{name: 'p1911', url: 'p1911.png'},{name: 'P92', url: 'P92.png'},{name: 'Pan', url: 'Pan.png'},{name: 'QBU', url: 'QBU.png'},{name: 'QBZ', url: 'QBZ.png'},{name: 'R1895', url: 'R1895.png'},{name: 'R45', url: 'R45.png'},{name: 'S12K', url: 'S12K.png'},{name: 'S1897', url: 'S1897.png'},{name: 'S686', url: 'S686.png'},{name: 'Sawed-off', url: 'Sawed-off.png'},{name: 'SCAR-L', url: 'SCAR-L.png'},{name: 'Scorpion', url: 'Scorpion.png'},{name: 'Sickle', url: 'Sickle.png'},{name: 'Signal', url: 'Signal.png'},{name: 'SKS', url: 'SKS.png'},{name: 'SLR', url: 'SLR.png'},{name: 'Thomson', url: 'Thomson.png'},{name: 'UMP9', url: 'UMP9.png'},{name: 'Vector', url: 'Vector.png'},{name: 'VSS', url: 'VSS.png'},{name: 'win94', url: 'win94.png'}];
let length = imglist.length;
let images = new Array(); // 定义一个数组容器,用来存储预加载完成的图片
let loadEl = document.querySelector('.loading');
function preload () {
let count = 0; // 计算器,计算加载了多少图片
for (let i = 0; i < length; i++) {
images[i] = new Image();
images[i].src = `./imgs/${imglist[i].url}`;
// 谷歌浏览器高版本支持大部分ES6,所以这里就不用字符串拼接了。
images[i].onload = function () {
count++;
if (count === length) {
loadEl.innerHTML = '加载完成';
} else {
loadEl.innerHTML = '正在加载中';
}
}
}
}
preload();
</script>
打开页面重新刷新一下,在控制台NetWork可以将图片全部加载出来。emmm,但是由于本地加载速度太快了,一下子就加载完成。通过下面截图可以看到,加载时间不到1s就加载,并不能很好看的预加载过程。
3、预加载图片真实环境模拟
所以为了小伙伴们能够更加直观的看到预加载的过程,这里我们决定进行真实环境模拟:
①这里我利用vscode自带的插件,生成一个本地服务器。
②然后在切换到浏览器控制台下NetWork,将网速调整为Fast3G
③ 然后将之前加载中的代码修改,成百分比显示。
// loadEl.innerHTML = '正在加载中';
loadEl.innerHTML = `正在加载中${Math.round(count / length * 100)}%`;
最终效果如下:
三、小结
好了!以上就是鄙人对于前端图片预加载一点简单理解与复习了,主要回顾一些image()基本属性点。
当然,前端图片预加载方法也并不止这么一种,方法还是有好几种。所以后续使用何种方法就各位小伙伴自己了。这里有一篇大佬翻译的文章就提到三种前端预加载的方法,希望可以给大家一个参考。
这篇文章中的第二个方法,就是本文采用的方法。所以希望各位大佬待会点进看完之后,不要出来打我。毕竟我不是大佬代码水平,我只是一个快乐前端段子手。
传送门地址:译:利用CSS、JavaScript及Ajax实现图片预加载的三大方法
考虑新年第一篇文章,吹水过多不在状态,所以良(很)心(皮)的我,决定锦上添花额外写一个快乐loading动画作为给我大哥赔罪。
快乐loading小动画
这里就是百分比数字,分割成两位,然后通过数字的不同,改变图片background-position
属性,来完成loading预加载动画。
images[i].onload = function () {
count++;
if (count === length) {
loadStart.style.display = 'none';
loadEnd.style.display = 'block';
loadEnd.onclick = function () {
alert('恭喜学习图片预加载!');
}
} else {
// loadEl.innerHTML = '正在加载中';
// loadEl.innerHTML = `正在加载中${Math.round(count / length * 100)}%`;
let text = Math.round(count / length * 100);
let text1 = parseInt(text / 10);
let text2 = parseInt(text % 10);
console.log(text1, text2);
num1.style.backgroundPositionX = `${-47 + text1 * -60}px`
num2.style.backgroundPositionX = `${-47 + text2 * -60}px`
}
}
所以对完整blogDemo代码感兴趣的,可以从本人github上阅览。
原创文章,文笔有限,才疏学浅,文中若有不正之处,再次再次再次欢迎各位啪啪的打脸赐教。(有句话说的好,重要的词得说三遍。)
我是车大棒!我为我自己带眼了!