但是,从用户体验的角度来说,等一张图加载完成再进行下一张加载是不友好的。数据提供方都应该直接把图片的高度在服务器处理好,json数据里面返回过来。网速很慢的时候,要等好久,然后一下子图片都出来了,不觉得很诡异吗?尤其是第三方接口。一加载不出来就出大问题了。
所幸的是,第三方提供了图片的宽高信息。
因此for循环还是可以有的,在返回的数据里面,有宽度和高度值。利用它们就可以实现定宽(255px)和定高(原始高度乘上一个比例)。
$(function(){ $.getJSON(createUrl(1),function(data){ console.log(data); for(var i=0;i<data.length;i++){ //console.log(data[i].preview); var $html=$('<div><img src="'https://www.jb51.net/+data[i].preview+'"><p>'+data[i].title+'</p></div>') $('li').eq(getShortestLi()).append($html); $html.find('img').css('height',(data[i].height*225/data[i].width)+'px'); $html.find('img').css('width','225px'); }; //console.log([$('li').eq(0).height(),$('li').eq(1).height(),$('li').eq(2).height(),$('li').eq(3).height()]) }) })
事实上个人认为这是最简单且用户体验最好的方案。
有了瀑布,还需要流
流的逻辑
往下拉(滚动),第一个底部进入可视区的li,优先加载。
换句话说,最短li的高度与该li到页面顶部之和小于滚动条高度和可视区高度之和时,触发li加载。
li的高度好求。但是最短li到页面顶部距离怎么求?
原生的方法可以这样实现:
function getTop(obj){ var iTop=0; while(obj){ iTop+=obj.offsetTop; obj=obj.offsetParent; }//累加元素本身和自身所有父级高度偏移值 return iTop; }
但是本案例既然是用jquery,自然有它的方法。
obj.offset().top
滚动事件
原生的实现方法是:window.onscroll=function(){...}
jquery的实现方法是:$(window).scroll(function(){...})
现在验证一下写出的代码代码有没问题
(window).scroll(function(){ var $li=$('li').eq(getShortestLi()); var scrollTop=document.documentElement.scrollTop||document.body.scrollTop; //console.log([$li.offset().top+$li.height(),document.documentElement.clientHeight+scrollTop]) //如果li高度与li到页面顶部的高度之和<可视区高度+滚动距离 if($li.offset().top+$li.height()<document.documentElement.clientHeight+scrollTop){ alert(1); } })
运行代码,发现第一个到底的li出现是可视区时,弹出1.证明可用。
因为涉及到滚动事件,所以getJSON相关函数应该封装为getList()方便调用。所以需要重新调整一下。
此时的代码是这样的:
//找出高度最小li的索引值 function getShortestLi(){ var shortest=0; for(var i=1;i<4;i++){ if($('li').eq(i).height()<$('li').eq(shortest).height()){ shortest=i; } } return shortest; } function createUrl(num){ return 'http://www.wookmark.com/api/json/popular?page='+num+'&callback=?'; } function getList(n){ $.getJSON(createUrl(n),function(data){ //console.log(data); for(var i=0;i<data.length;i++){ var $html=var $html=$('<div><img src="'https://www.jb51.net/+data[i].preview+'"><p>'+data[i].title+'</p></div>'); //console.log(data[i].height); $('li').eq(getShortestLi()).append($html); dataArr[i].height*=225/dataArr[i].width; $html.find('img').css('height',dataArr[i].height+'px'); $html.find('img').css('width','225px'); }; } $(function(){ var pageNum=1; getList(pageNum); $(window).scroll(function(){ var $li=$('li').eq(getShortestLi(); var scrollTop=document.documentElement.scrollTop||document.body.scrollTop; if($li.offset().top+$li.height()<document.documentElement.clientHeight+scrollTop){ pageNum++; console.log(pageNum); getList(pageNum); } }) })
这样一来,好像可以实现了。但是一看控制台的console.log,又发现问题。
如厕的逻辑
在触发加载前提时,图片正在加载,期间动了滚动条,就又触发第二次加载,再动一下,就触发第三次,于是短短一瞬间,触发了n次加载。
那就做一个开关吧。