年前网站的首页要改版,不知怎么的这个艰巨的任务就到了我头上,首页作为网站的门面,感觉压力很大,但是也是一次难得的锻炼的机会,所以还有点儿兴奋的就开始做了。
这次的改版跟京东淘宝的首页很像,首屏是商品分类、轮播、滚动的促销厂家信息和大家都在买、推荐商品以及公告这几个模块,剩下模块的则分为不同的楼层展示,新首页现在具体长这样:我是新首页
因为首页有很多商品和广告图片,我开始的时候用了懒加载,当楼层滚动到可视区时对楼层图片路径进行替换,但是这样仍然存在一些问题(如下),我们老大发话让照着京东的效果做,我就在网上各种找资料,终于,在京东首页的console里面找到了我想要的:https://aotu.io ,里面就有关于京东首页最近这次改版的一篇技术文章,还有好多高大上的资料,有兴趣的同学可以看一下。下面说说这次首页加载遇到的几个问题和解决方案。
1 优先加载
问题:打开首页,当用户快速滚动到下面的楼层时,下面的楼层要等到上面的几个楼层的图片都加载完了才开始加载,这样下面的楼层图片等待加载的时候就会很长,用户会觉得页面很卡。
解决方案:对滚动事件进行优化,也就是传说中的函数节流(这个会再新开一篇详细总结),使用setTimeout控制滚动时函数执行的频率,我的间隔时间是300ms,当用户快速滚动时因为还没超过300ms,所以快速滚动经过的楼层的加载函数不会执行,实现了优先加载的效果。
代码:
function priorLoad() { var floors = $(".lazyLoad"); if (!floors) { return; } loadFlag = false; var clientH = document.documentElement.clientHeight; //可视区高度 timer = setTimeout(function () { var scrollT = document.documentElement.scrollTop || document.body.scrollTop; //滚动高度 for (var i = 0; i < floors.length; i++) { //判断每个楼层是否已经加载过 if (floors[i].getAttribute("loaded") != "1") { var t = getTop(floors[i]); if ((scrollT - floors[i].offsetHeight) <= t && t <= (scrollT + clientH)) { //如果滚动的高度加屏幕高度大于楼层距离顶部的高度,说明楼层显示在屏幕中 var imgs = $(floors[i]).find(".visible-img"); var count = 0; for (var k = 0; k < imgs.length; k++) { //对未加载过且需要懒加载且是显示的图片进行加载 if (imgs[k].getAttribute("loaded") != 1) { imgs[k].src = imgs[k].getAttribute("_src"); imgs[k].setAttribute("loaded", 1); //加载后改变加载标示 imgs[k].onload = function () { count++; if (count == imgs.length) {
floors[i].setAttribute("loaded","1");
$(floors[i]).removeClass("lazyLoad"); loadFlag = true; autoLoad(); } } } } } } } }, 300); }
2 首屏直出
问题:首屏轮播图片的位置会闪一下空白然后才开始加载图片,这个是因为首页的数据都是js异步请求的,在发送请求并且返回数据的时间里轮播那里就会出现空白。
解决方案:京东采用的方式是首屏数据由服务器直接输出,包括轮播图的第一帧,但是我们的网站因为有些信息是根据地区挂钩的,实现有些难度,所以这个方案没有采用
3 空闲加载
问题:因为是懒加载,只有楼层出现在可视区的时候才开始加载,当用户打开首页没有向下滚动的时候,下面的楼层一直显示的是正在加载的图片。
解决方案:为了保证首屏的加载速度,当首屏数据加载完成之后,自动对下面的楼层按序加载,这样等用户向下滚动的时候下面的楼层已经加载一部分甚至加载完了,提高用户体验。
代码:
function autoLoad() { var floors = $(".lazyLoad"); if (floors.length == 0) { return; //所有楼层都加载完了 } var obj = floors[0]; if (loadFlag) { if (obj.getAttribute("loaded") != "1") { loadFlag = false; var imgCount = 0; var imgs = $(obj).find(".visible-img"); for (var k = 0; k < imgs.length; k++) { //对未加载过且需要懒加载且是显示的图片进行加载 if (imgs[k].getAttribute("loaded") != 1) { imgs[k].src = imgs[k].getAttribute("_src"); imgs[k].setAttribute("loaded", 1); //加载后改变加载标示 imgs[k].onload = function () { imgCount++; if (imgCount == imgs.length) { //该楼层的数据已经加载完 obj.setAttribute("loaded", "1"); $(obj).removeClass("lazyLoad"); loadFlag = true; autoLoad(); //递归加载下一个楼层 } } } } } } }
4 显示的数据先加载
问题:楼层的二级分类都是以选项卡的形式展示的,所以除了显示的分类其他的分类数据都是隐藏的,这些隐藏的数据加载会影响整个楼层的加载速度。
解决方案:在楼层加载的函数里加条件判断,只对未加载过的并且是显示中的图片进行加载,过滤掉隐藏的图片,提高加载速度。
代码:
function displayLoad() { var floors = $(".floor"); //所有楼层下的第一个展示的分类 for (var i = 0; i < floors.length; i++) { var t = getTop(floors[i]); //每个楼层的top值 var imgs = floors[i].getElementsByTagName("img"); for (var k = 0; k < imgs.length; k++) { if (imgs[k].getAttribute("_src") && imgs[k].getAttribute("loaded") != 1 && $(imgs[k]).is(':visible')) { imgs[k].src = imgs[k].getAttribute("_src"); imgs[k].setAttribute("loaded", 1); } } } }
5 使用webp格式图片,这种图片只有jpg格式图片的3/2,但是只兼容weikit内核的浏览器,这版本首页还没用,但是是一种优化的方式。