版权声明:转载请注明来源。

本文链接: http://www.ptbird.cn/2016/07/03/pubuliu/




摘要:总所周知,百度搜图结果下拉会越来越多自动呈现,成为瀑布流。想要打造类似百度图片搜索的瀑布流不是困难的事情,通过JavaScript也能实现只是实现的比较麻烦,通过jQuery实现50+行代码即可。而且相比百度的样式,更加自由化!


废话不多说,先上图:

下图最终的效果图,比较丑,是因为图片我没有经过处理,随便找的图片。

照片特点宽度全部相同,高度不相同。 
(注:百度图片宽度不同,高度相同—改版之后)

11111


下面就是实现瀑布流:

一、原理简介

二、文档列表

三、实现过程

四、相关问题


一、原理:

1、从上图可以看出,瀑布流无非是让高度不想同的图片能够按照一定的规律,顺序排列下来。下面给出一示意图,介绍瀑布流原理。


11111


假设一排网页只能显示四张图片,第一排蓝色四张图片已经显示完成。可以看出,第二排的排列是无顺序的,或者说是某种隐藏的顺序。 
什么意思呢? 
第二排第一张一定是放在第一排高度最短的那张图片后面的。【请仔细斟酌着句话】 
然后依次根据高度进行放置第二排的图片。为什么要这样子防治呢?无非是为了更好地贴合第一排的摆放情况,从而达到无缝对接(这里的无缝是指本实例中,每张图片的外边距都为0),最终形成瀑布流。 
请思考,第三排第一张图片应该摆放在那里? A/B/C/D??

而瀑布流的主要思想就是按照这种顺序进行排列。

当然最终的屏幕滚动监听属于高级思想的扩展。


二、本实例文档说明

  • img文件夹 
    • 存放十张图片
  • jquery.js
  • app.js (瀑布流实现js)
  • style.css (图片样式控制)
  • index.html (显示界面)


11111



三、jquery实现瀑布流

首先是**

index.html

**代码说明:

很简单就是放了几个div,然后几张图片:

主要结构为:

  • 图片放在class为content的盒子中,然后父盒子是box,然后外面最大为contianer
  • 头部也很简单。

    (为方便查看,将图片的div只写了一个,实际上是写了20多个。)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Jquery 瀑布流</title>
    <link rel="stylesheet" href="./style.css">
    <script src="./jquery.js"></script>
    <script src="./app.js"></script>
</head>
<body>
    <div id="container">
        <div class="box">
            <div class="content">
                <img src="./img/1.jpg" alt="1">
            </div>
        </div>
    </div>
</body>

**

style.css

**代码说明:

唯一注意的是:

所有的图片宽度都应该相等,只是高度不等。

/*
    第二排第一张图片应该放在第一排中高度最小的图片的下方.
 */
*{
    padding:0;
    margin:0;
 }/*消除所有的边距*/
.box{
    position:relative;
    float:left;
}/*所有盒子左浮动*/
.content{
    padding:10px;
    border:1px solid #ccc;
    box-shadow: 0 0 5px #ccc;
    border-radius:5px;
}/*盒子基本样式,即图片的基本状态*/
.content img{
    width:190px;
    height:auto;
}/* 所有的图片需要等宽度!!! */

**

app.js

**代码说明:

第一部分:实现第二排第一张图片放在第一排高度最小的图片的下方.

通过函数 imgLocation() 实现

基本思想:

  • 操作DOM来获取盒子的宽度,随便一个DOM IMG就能做到
  • 通过img宽度和window窗口宽度来计算一排能放几张图片
  • 将第一排的图片的高度存在数组boxArr[ ]中,为了后面的高度比较
  • 放置第二排时,首先考虑第一排盒子的高度,从数组中获取最小高度,然后图片的位置确定。
  • 图片位置确定的方式很简单:
$(value).css({ 
‘position’:’absolute’, 
‘top’:minBoxHeight, 
‘left’:box.eq(minBoxIndex).position().left 
});
//通过上述代码就能做到,其中value为返回的迭代对象,通过操作css定位来固定位置。

最后很重要的一步:添加图片后,该列上的图片高度实际上是变化了,因为高度要加上刚放上去的图片的高度,因此需要进行高度的计算后,重新放在数组中,否则就会出现第二排开始,所有图片都叠在一起了。



【详细解释,见代码!!!】

function imgLocation(){
    var box=$('.box');
    var boxWidth=box.eq(0).width();
        /*
            通过qu(0)来获取第一个盒子的宽度
            宽度都相同,因此获取那个box的宽度都可以。
         */
    var num=Math.floor($(window).width()/boxWidth);
        /*
            计算一排能放几个图片 num
            取整数。
         */
    var boxArr=[]; //存储盒子的高度
    box.each(function(index,value){
        /*
            index:确定从哪个图片开始
            value:确定当前是哪个对象
         */
        // console.log(index+"  "+value);
        var boxHeight = box.eq(index).height();
            /*
            获取每个盒子的高度
            其中第一排直接放在数组中。
             */
        if(index<num){
            boxArr[index] = boxHeight;
        }else{
            var minBoxHeight=Math.min.apply(null,boxArr);
            var minBoxIndex=$.inArray(minBoxHeight,boxArr);
            /*
                当放置第二排时,需要考虑第一排的高度
                获取最小盒子的高度
                从数组中获取最小盒子的位置,从而为了放置下一排的盒子。
             */
             $(value).css({
                 'position':'absolute',
                 'top':minBoxHeight,
                 'left':box.eq(minBoxIndex).position().left
             });
             /*
                获取图片的对象,然后对图像进行操作。
                实际上操作的是box,位置的放置通过CSS来控制。
              */
             boxArr[minBoxIndex]+=box.eq(index).height();
             /*
                当第二排的第一张图片添加完后,重新计算高度,否则所有的图片都叠在
                第一排的最低的图片下面。
             */
        }
    });
}

通过上述函数,就能够灵活的操作图片的位置摆放,但是有一个很重要的问题没有解决:

我们的图片是不确定数量的,需要通过浏览器滚动监听来实现相关的图片加载,而这一步又应该怎么实现呢?

其实这个也不难。

首先需要了解一个函数:

scrollside()

函数的主要作用为:

判断是否需要加载图片,通过监听浏览器窗口高度来实现
具体为: 

 1、先获取最后一张图片的高度,也就是我们之前固定的能够铺满整个浏览器的一次页面的图片中的最高高度。

 2、获取屏幕高度,再获取滚动的高度(滚动距离顶端的高度)。

 3、当前文档高度+滚动高度 如果大于当前图片的最高高度时就进行图片的加载!!

代码如下:

function scrollside(){
    var box=$('.box');
    var lastboxHeight = box.last().get(0).offsetTop+Math.floor(box.last().height()/2);
        /*
            获取最后一个盒子的高度也就是最高的盒子的高度。
         */
    var documentHeight=$(document).width();
        //获取当前屏幕的高度
    var scrollHeight=$(window).scrollTop();
        //获取窗口的滚动高度 滚动到距顶端的位置
        // console.log(scrollHeight+"  "+documentHeight);
    return (lastboxHeight<scrollHeight+documentHeight)?true:false;
    /*
        当前文档的高度+滚动的高度大于最高的图片的高度的时候,进行图片的加载。
     */
}

那么问题又来了:


该怎样去应用这两个函数呢??


基本思想:

1、首先在文档加载完之后进行第一次图片的排放,这次的排放目的是为了铺满一次浏览器页面。

2、var dataTmg={“data”:[{“src”:”1.jpg”},{“src”:”4.jpg”},{“src”:”2.jpg”},{“src”:”3.jpg”}]};

通过json数据【该数据理论上应该从服务器返回来,这个数据是作为鼠标滚动时,图片加载的备用加载源】

3、通过window.onscroll来监听屏幕的滚动,然后进行之前 scrollside函数的确认是否进行图片的瀑布加载。

4、进行图片的加载之后,在进行图片的“序列化排列”。

代码如下:

$(document).ready(function(){
    $(window).on("load",function(){
        imgLocation();
        var dataTmg={"data":[{"src":"1.jpg"},{"src":"4.jpg"},{"src":"2.jpg"},{"src":"3.jpg"}]};
            //json数据存放图片的地址,用于扩充图片时候使用。
         window.onscroll=function(){
        /*
            通过屏幕的滚动来加载图片
         */
            if(scrollside()){
                $.each(dataTmg.data,function(index,value){
                    //循环进行json数据的读取和函数的调用
                    var box=$("<div>").addClass('box').appendTo($('#container'));
                    //添加一个box到container下面
                    var content = $('<div>').addClass('content').appendTo(box);
                    // console.log('./img/'+$(value).attr('src'));
                    $('<img>').attr('src','./img/'+$(value).attr('src')).appendTo(content);
                        //添加如片到内容
                    imgLocation();
                        //创建出图片后,需要重新添加图片。
                });
            }
         }
     });
});



通过上面的操作,我们可以很轻松的就实现了瀑布流,但是依旧存在几个比较容易出错的地方.



四、常见错误


1、图片叠加到一张图片上去.


原因是没有在下一排的图片排列上去时进行高度的重新计算

2、屏幕滚动无效果

原因是屏幕滚动监听部分高度获取和计算有问题。请注意滚动高度是如何计算的。



五、重要补充


实际上瀑布流的中心流程是:


先把图片全部都放在网页上,然后对网页上的图片数量和高度进行重新计算,重新排列,进而形成瀑布流模式。


实际上不是预先判断好往哪里放,然后再放。


这个很重要。




代码托管在: 
http://git.oschina.net/postbird/IMGWaterfallFlow【见附件】

有任何指教请直接留言,谢谢、

By postbird.2016-1-10