前言

同往常一样,利用课后闲暇的时光撸出来的颇具实用意义的小效果。代码量虽然多了点,但实现的思路,显示的流程格外清晰。个人认为这个是学习JS,活跃思维,灵活运用的一个较为典型的学习案例。同一个瀑布流的效果但实现方式却很多,利用递归、冒泡等等手法都可以达到你想要的目的。这次要说的就是利用类似递归来实现此效果的原创方案。此方案个人认为难度系数较低(只要充分理解本人的实现原理),看官们要出现理解不能的情况时大可以在文下发表评论,只要我看到了一定会为你解答。当然也可以根据自身水平到网上查找其他的实现方案。

Code

为助于更好的理解,本人已加详细的注释用以说明。(正好也验证了一句老话:程序员最烦自己写注释,但又更怕别人没注释。。。。)


<?php
//没有数据源,利用遍历对应文件夹中的所有的图片得到的数组模拟成数据源
$arr = array();
$dir = opendir('./images');
while($file = readdir($dir)){
    if($file == '.' || $file == '..'){
        continue;
    }
    $arr[] = $file;
}
closedir($dir);
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>瀑布流</title>
<style type="text/css">
*{padding:0;
    margin:0
}
.box{
    padding:5px;
    float:left;
}
.image{
    padding:5px;
    border:1px solid #ccc;
    box-shadow: 0 0 5px #ccc;
    border-radius:5px;
}
.image img{
    width:150px;
    height:auto;
}
</style>
</head>
<body>
<div id="container" style="">
<?php foreach($arr as $val):?>
<div class="box">
<div class="image">
<img src="./images/<?php echo $val?>" />
</div>
</div>
<?php endforeach;
?>
</div>
</body>
<script>
window.onload = function(){
    imgLocation('container','box');
}
window.onresize = function(){
    imgLocation('container','box');
}
function imgLocation(parent,content){
    //取得大盒子的节点对象
    var cparent = document.getElementById(parent);
    //从大盒子中找到所有放图片的盒子
    var ccontent = getChildElement(cparent,content);
    //由于CSS已经规定所有Img的宽度为150,所以这边返回的图片盒子的宽度就是150+5*2+5*2+2 = 172;
    var imgWidth = ccontent[0].offsetWidth;
    //利用body体宽度和图片盒子所在宽度两者相除得到目前宽度下第一排能摆放的最大个数
    var cols = Math.floor(document.documentElement.clientWidth / imgWidth);
    //利用计算出来的一排最多的个数乘以每个图片的宽度得到大盒子应有的宽度
    cparent.style.cssText = 'width:'+imgWidth*cols+'px;margin:0 auto;';
    console.log(cols);
    //定义用于存放第一排图片盒子的高度所用的数组
    var BoxHeightArr = [];
    //循环遍历所有图片盒子
    for (var i=0;i<ccontent.length;i++){
        //利用i的自增获取第一排所有盒子的高度(这里设计的很巧妙哦)
        if(i<cols){
            //将第一排所有盒子的高度追加到之前定义的数组
            BoxHeightArr[i] = ccontent[i].offsetHeight;
            //并且把第一排盒子所有的绝对定位去掉,不然在实时拉伸窗口的时候会破坏自适应
            ccontent[i].style.position = '';
        } else{
            //循环完第一排时利用取到的高度数组从中获取到最小高度
            var minHeight = Math.min.apply(null,BoxHeightArr);
            //自定义函数取得最小高度所在的盒子的位置(下标)
            var minIndex = getminHeightLocation(BoxHeightArr,minHeight);
            //修改第二排开始摆放的CSS,盒子定位修改成绝对定位,为后面的移动最准备
            ccontent[i].style.position = 'absolute';
            //把当前循环盒子的Y坐标修改成最小盒子的高度(这样就可以让当前盒子排在第一排最小盒子的下面)
            ccontent[i].style.top = minHeight + 'px';
            //把当前循环盒子的X坐标修改成最小盒子所在位置的X坐标(达到对齐效果)
            ccontent[i].style.left = ccontent[minIndex].offsetLeft + 'px';
            //当本轮循环的修改操作全部完成后,更新第一排盒子高度的数组里的最小高度
            //现在最小盒子的高度应该是之前的高度加上第二排追加上来的盒子的高度
            //以此循环操作所有的盒子就能实现瀑布流的效果
            BoxHeightArr[minIndex] = BoxHeightArr[minIndex]+ccontent[i].offsetHeight;
        }
    }
}
//以下开始是辅助部分,不一一赘述,上面是实现的核心,原理已经一一道明
function getChildElement(parent,content){
    var contentArr = [];
    var allcontent = parent.getElementsByTagName('*');
    for (var i=0;i<allcontent.length;i++){
        if(allcontent[i].className == content){
            contentArr.push(allcontent[i]);
        }
    }
    return contentArr;
}
function getminHeightLocation(BoxHeightArr,minHeight){
    for (var i=0;i<BoxHeightArr.length;i++){
        if(BoxHeightArr[i] == minHeight){
            return i;
        }
    }
}
</script>
</html>

最终效果


一介布衣