It's all about the beginning.
There are two types of waterfall layouts, one is a fixed column and the other is a non-fixed column. This paper mainly describes the implementation of the first kind.
Fixed columns are characterized in that the total number of columns per row is the same regardless of how the page is scaled.
A row of 4-column waterfall flows from the layout point of view, is 4 Li tags. The data is added dynamically to the page by a certain event, such as how many px the scroll bar scrolls through, and then read.
The principle of adding data is not based on Li index values but dynamically added according to the shortest column in each column. Otherwise, the page may be difficult to read (the left and right height is not uniform).
An instance involves an Ajax method. Can be run in a server environment.
There's no more nonsense to say. directly on the style.
<ul id= "UL1" >
<li>
<div>
<p> I'm a text description I'm a text description I'm a text description I'm a text description I'm a text description I'm a text description </p>
</div>
</li>
<li>
<div>
<p> I am a text description I am a text description I am a text description I am a text description I am a writing description
</p>
</div >
</li>
<li>
<div>
<p> I'm a text description I'm a text description I'm a text description I'm a text description I'm a text description I'm a text description </p>
</div>
</li>
<li>
<div >
<p> I am a text description I am a text description I am a text description I am a text description I am writing description
</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;p adding:10px;
margin-bottom:10px;
}
Li Div img{
width:225px;display:block;
}
Basic effect as shown:
When the style shows no problem, delete the code inside the LI.
The next step is to add it dynamically via Ajax.
Where does the data come from?
Here is the Wookmark data interface.
Http://www.wookmark.com/api/json/popular?page=1
Dot open URL to get is a JSON.
The amount of information is large. What's the analysis?
You can usually look at the document. But with no documentation on hand, you can look at the links. Return to what a ghost.
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 prints the result:
The original is an array of 50 picture information. Each array element is a JSON. In this simple demo, only need to take the preview attribute and title property for the time being.
Layout implementation
One of the keys is to judge the shortest Li, in fact we need the shortest height of Li's index value.
Locate the index value
function Getshortestli () {
var shortest=0 of the height min li;
for (Var i=1;i<4;i++) {
if ($ ("Li"). EQ (i) Height () <$ (' li ')-eq (shortest). Height ()) {
shortest=i;
}
} return
shortest;
}
And then there's the Getjson method.
$ (function () {
$.getjson (CreateURL (1), function (data) {
//console.log (data);
for (Var i=0;i<dataarr.length;i++) {
var $html =$ (' <div><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 ())
})
})
Then load the look, the layout is out. Simple and beautiful.
Do it, it looks like everything is fine. But there is a fatal problem lurking in it.
For the loop, the trouble?
Look at the Console.log information. For analysis, I put the height of 4 li into an array:
50 pictures are divided into 4 columns, and the average height is three thousand or four thousand pixels.
And to the end of the loop, the program to judge the end of the only heinous more than 1000 px, because the picture loading process is slower than the for loop execution speed. Although the display in the demo is normal, but this code in a bad speed, will cause work accidents.
Thought one: You can determine whether the picture is loaded and completed.
You can use a timer to monitor, and then recursive implementation, my plan is this
var index=0;
function Loadpic (index) {
var $html =$ (' <div><p> ' +data[ Index].title+ ' </p></div> ')
$ (' li '). EQ (Getshortestli ()). append ($html);
var oimg= $html. Find (' img ');
var t=setinterval (function () {if
(Oimg.height ()!=0) {//if finished loading.
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)/Every 50ms monitor once
}
loadpic (0);
However, from the user experience point of view, it is unfriendly to wait for a picture to load and then proceed to the next load. The data provider should be able to direct the image height to the server and return it to the JSON data. Speed is very slow time, to wait for a long time, and then suddenly the pictures are out, do not feel very strange? In particular, third-party interfaces. It's a big problem if you can't load it up.
Fortunately, the third party provides a picture of the wide-height information.
So the For loop is still available, with the width and height values in the returned data. They can be used to achieve a fixed width (255px) and a fixed height (the original height 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><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, personally think this is the simplest and best user experience.
With waterfalls, we need to flow.
The logic of the stream
Pull down (scrolling), the first bottom into the visible area of Li, priority loading.
In other words, the height of the shortest Li and the sum of the Li to the top of the page is smaller than the height of the scroll bar and the height of the visible area , triggering Li loading.
Li's height is well begged. But the shortest Li to the top of the page how to ask?
Native methods can be implemented in this way:
function GetTop (obj) {
var itop=0;
while (obj) {
itop+=obj.offsettop;
obj=obj.offsetparent;
} The cumulative element itself and all of its parent height offsets return
itop.
But in this case, with jquery, there is a natural way to do it.
obj.offset().top
Scrolling events
The native realization method is:window.onscroll=function(){...}
jquery is implemented in the following ways:$(window).scroll(function(){...})
Now verify that the code you wrote is not a problem.
(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])
// If Li height with Li to the top of the page and the height of the < visual area height + scrolling distance if
($li. Offset () top+ $li. Height () < Document.documentelement.clientheight+scrolltop) {
alert (1);
}
})
Run the code and find that the first one in the end is the visible area when the Li appears, pop 1. Proof available.
Because it involves scrolling events, the Getjson correlation function should be encapsulated as getlist () for easy invocation. So we need to readjust.
The code at this point is this:
Locate the index value function Getshortestli () {var shortest=0 of the height min li;
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><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);
}
})
})
As a result, it seems to be achieved. But a look at the console.log of the console, and found the problem.
The logic of Potty
In the trigger loading premise, the picture is loading, during the movement of the scroll bar, and then trigger the second load, and then move again, triggered the third time, so a short moment, triggering n load.
Then make a switch.
Just like the logic of a public toilet. n A person queues into a pit bit. People outside want to go in first to determine whether the door is locked. No lock to enter. The first thing to lock the door after entering. When the toilet is finished, the door opens. The people in the back can get in.
The new setting is a switch bcheck and the default is true.
When the load condition is triggered, it is also necessary to determine if the bcheck is true (the door is open) and to trigger the getlist () (toilet) when it is true. Otherwise return false (can wait only).
GetList first set the bcheck to False (lock the door before going to the toilet). Wait until the GetList callback function executes to the end. Then set the bcheck to True (open the door).
This paragraph does not stick to the code.
There's always a day to run.
When the data is finished (everyone is on the toilet), there is no need to load it (automatically lock the door).
So after locking the door in the Getjson callback function to find an empty array, it is judged, and when the length of the data is empty, the direct returnfalse. Then the bcheck will be closed forever.
All the code is as follows:
Locate the index value function Getshortestli () {var shortest=0 of the height min li;
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.length;i++) {//console.log (Data[i].preview);
var $html =$ (' <div><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 ');
};
} bcheck=true;
});
} $ (function () {var pagenum=1;
GetList (Pagenum);
$ (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])// If Li height with Li to the top of the page and the height of the < visual area height + scrolling distance if ($li. Offset () top+ $li. Height () <document.documentelement.clientheight+
ScrollTop) {if (bcheck) {bcheck=false;
pagenum++;
Console.log (Pagenum);
GetList (Pagenum);
}else{return false; }
}
})
})
Above is the entire content of this article, I hope the content of this article for everyone's study or work can bring some help, but also hope that a lot of support cloud Habitat community!