is the principle that will be mentioned at the beginning
There are two types of waterfall flow layouts, one is fixed columns and the other is non-fixed columns. This article mainly describes the implementation of the first type.
The characteristic of fixed columns is: no matter how the page is scaled, the total number of columns in each row is the same.
From a layout perspective, a waterfall flow with one row and four columns is four li tags. Through certain events (such as how many px the scroll bar scrolls), then read it, and then dynamically add the data to the page.
The principle of adding data is not to add based on the li index value, but to add dynamically based on the column with the shortest height among the columns. Otherwise, the page may be ugly (the left and right heights are not uniform).
The example involves the ajax method. Can be run in a server environment.
stop bullshitting. Apply the style directly.
<ul id="ul1"> <li> <div> <img src="images/1.jpg" alt="jquery implements simple waterfall flow layout" > <p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p> </div> </li> <li> <div> <img src="images/2.jpg" alt="jquery implements simple waterfall flow layout" > <p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p> </div> </li> <li> <div> <img src="images/3.jpg" alt="jquery implements simple waterfall flow layout" > <p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p> </div> </li> <li> <div> <img src="images/4.jpg" alt="jquery implements simple waterfall flow layout" > <p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p> </div> </li> </ul>
css
*{ margin:0; padding: 0; } ul li{ list-style: none; } #ul1{ width: 1080px; margin: 100px auto 0; } li{ width: 247px; float: left; margin-right: 10px; } li div{ border:1px solid #000;padding:10px; margin-bottom:10px; } li div img{ width: 225px;display: block; }
The basic effect is as shown in the figure:
After the style is displayed correctly, delete the code in li.
Next, add it dynamically through ajax.
Where does the data come from?
The data interface of wookmark is used here.
http://www.wookmark.com/api/json/popular?page=1
Click on the url to get a json.
A lot of information. How to analyze?
Generally, you can read the documentation. But if you don’t have the document at hand, you can look at the link. What the hell is return.
function createUrl(num){ return 'http://www.wookmark.com/api/json/popular?page='+num+'&callback=?'; } $(function(){ $.getJSON(createUrl(1),function(data){ console.log(data); }) })
The console print result is:
It turns out to be an array composed of 50 picture information. Each array element is a json. In this simple demo, you only need to get the preview attribute and title attribute for the time being.
Layout implementation
One of the keys is to determine the shortest li. In fact, we need the index value of the shortest height li.
//找出高度最小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; }
Then there is the getJSON method
$(function(){ $.getJSON(createUrl(1),function(data){ //console.log(data); for(var i=0;i<dataArr.length;i++){ var $html=$('<div><img src="'+data[i].preview+'" alt="jquery implements simple waterfall flow layout" ><p>'+data[i].title+'</p></div>'); //console.log($('li').eq(getShortestLi()).height()) $('li').eq(getShortestLi()).append($html); }; console.log([$('li').eq(0).height(),$('li').eq(1).height(),$('li').eq(2).height(),$('li').eq(3).height()]) }) })
Load it again and the layout will come out. Simple and beautiful.
At this point, everything looks fine. But there's a fatal problem lurking.
The for loop is causing trouble?
Look at the console.log information. For analysis, I put the heights of the four li's into an array:
The 50 pictures are divided into 4 columns. The average height must be three to four thousand pixels at least.
At the end of the loop, the end point judged by the program is only an outrageous 1,000 px, because the image loading process is slower than the for loop execution speed. Although the display in the demo is normal, this kind of code can cause work accidents when the network speed is not good.
Idea 1: You can determine whether the image is loaded.
You can use a timer to monitor it, and then use recursion to implement it. My plan is like this
var index=0; function LoadPic(index){ var $html=$('<div><img src="'+data[index].preview+'" alt="jquery implements simple waterfall flow layout" ><p>'+data[index].title+'</p></div>') $('li').eq(getShortestLi()).append($html); var oImg=$html.find('img'); var t=setInterval(function(){ if(oImg.height()!=0){//如果加载完了。 clearInterval(t); //console.log([$('li').eq(0).height(),$('li').eq(1).height(),$('li').eq(2).height(),$('li').eq(3).height()]) if(index<50){ return LoadPic(index+1); }else{ return false; } }else{ console.log('wait') } },50)//每隔50ms监听一次 } LoadPic(0);
However, from the perspective of user experience, wait until a picture is loaded before proceeding. One load is unfriendly. Data providers should directly process the height of the image on the server and return it in json data. When the Internet speed is very slow, you have to wait for a long time, and then all the pictures come out all of a sudden. Don’t you think it’s weird? Especially third-party interfaces. Once it fails to load, there is a big problem.
Fortunately, the third party provides the width and height information of the image.
So you can still have a for loop. In the returned data, there are width and height values. Using them, you can achieve fixed width (255px) and fixed height (original height multiplied by a ratio).
$(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="'+data[i].preview+'" alt="jquery implements simple waterfall flow layout" ><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()]) }) })
In fact, I personally think this is the simplest solution with the best user experience.
With the waterfall, we also need to flow
The logic of the flow
Pull down (scroll), the first li that enters the visual area at the bottom is loaded first.
In other words, when the sum of the height of the shortest li and the li to the top of the page is less than the sum of the height of the scroll bar and the height of the visual area, the li loading is triggered.
The height of li is easy to find. But how to find the shortest distance from li to the top of the page?
The native method can be implemented like this:
function getTop(obj){ var iTop=0; while(obj){ iTop+=obj.offsetTop; obj=obj.offsetParent; }//累加元素本身和自身所有父级高度偏移值 return iTop; }
But since this case uses jquery, it naturally has its own method.
obj.offset().top
Scroll event
The native implementation method is: window.onscroll=function(){...}
The implementation method of jquery is: $(window).scroll(function(){...})
Now verify whether there is any problem with the written code
(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); } })
Run the code, When it is found that the first li to the bottom appears in the visible area, 1 will pop up to prove that it is available.
Because scrolling events are involved, getJSON related functions should be encapsulated as getList() for easy calling. So it needs to be readjusted.
The code at this time is like this:
//找出高度最小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[i].title+'
In this way, it seems that it can be achieved. But when I looked at the console.log, I found another problem.
The logic of going to the toilet
在触发加载前提时,图片正在加载,期间动了滚动条,就又触发第二次加载,再动一下,就触发第三次,于是短短一瞬间,触发了n次加载。
那就做一个开关吧。
就跟公厕逻辑一样。n个人排队进一个坑位。外面的人想要进去首先得判断门是否锁上了。没锁才能进。进去之后第一件事把门锁上。等如厕完毕,门就打开。后面的人才能进
新设置一个开关bCheck,默认为true。
到触发加载条件时,还要判断bCheck是否为真(门开),为真时才能触发getList()(如厕)。否则return false(只能等)。
getList一开始就把bCheck设为false(如厕前先锁门)。等到getList回调函数执行到尾声。再把bCheck设为true(开门)。
这一段不贴代码了。
总有流完的一天。
当数据结束时(所有人上完厕所),就没有必要再进行加载了(自动把门锁上)。
所以在getJSON回调函数内锁门之后发现进来的是个空数组,那就进行判断,当获取到data的length为空时,直接returnfalse。那么bCheck就永远关上了。
全部代码如下:
//找出高度最小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=?'; } var bCheck=false; function getList(n){ $.getJSON(createUrl(n),function(data){ if(data.length==0){ return false; }else{ for(var i=0;i'+data[i].title+'
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持PHP中文网!
更多jquery implements simple waterfall flow layout相关文章请关注PHP中文网!