使用原生javascript实现瀑布流

简介

瀑布流布局是一种很常见的布局方式,他的主要视觉体验为图片元素等宽不等高,图片元素之间的水平排序参差不齐,而且随着滚动条的滚动,数据会进行异步的加载,这样的布局有两个好处,1-有视觉的冲击力,比较好看;2-图片元素能够保持原始比例,不会被拉伸。最终浏览器中看到的效果如下图:

HTML和CSS实现步骤

步骤1:确定html布局,代码(部分)如下

<div id="main">
    <div class="box">
        <div class="pic">
            <img src="img/1.jpg"/>
        </div>
    </div>
    <div class="box">
        <div class="pic">
            <img src="img/2.jpg"/>
        </div>
    </div>
</div>

其中class=box的div主要作用是控制定位,class=pic的div的主要作用是实现各种效果,如边框阴影

步骤2:用css实现上图的效果

*{margin: 0px; padding: 0px;}
#main{
    position: relative;
}

.box{
    padding: 15px 0 0 15px;
    float: left;
}

.pic{
    border: 1px solid #ccc;
    border-radius: 5px;
    box-shadow: 5px 5px 5px #CCCCCC;
    padding: 10px;
}

.pic img{
    width: 165px;
    height: auto;
}

注意:这里我们为什么不直接设置class=pic的margin值作为div之间的间隔,而是在外面又套了一层div呢?因为使用javascript中outerwidth属性能直接算出元素padding+margin+boder的值,而使用margin不能做到这一点。

javascript实现步骤

步骤1:取出所有div[class=box],放到变量var oBoxs中

步骤2:算出屏幕可视区域能容纳div[class=box]的个数,把个数放到var cols中

步骤3:遍历oBoxs,把前cols个div的高度放到变量oBoxsH中

步骤4:找出oBoxsH中的最小值及其索引,把下一个div的top值设置成为oBoxsH中的最小值,left的值设置成为oBoxsH中的最小值及的索引x当前div的宽度

步骤5:更新oBoxsH的最小值

步骤6:判断滚动的临界点,并加载数据

 // 瀑布流主方法
function waterfall(parent,box){
  var oParent=document.getElementById(parent);
  var oBoxs=getByClass(oParent,box);
  var cols = Math.floor(document.documentElement.offsetWidth/oBoxs[0].offsetWidth);
  var oBoxsH = [];
    for(var i=0;i<oBoxs.length;i++){
    if(i<cols){
       // 将图片的高度值添加到数组中
       oBoxsH.push(oBoxs[i].offsetHeight);
    }else{
      // 求最小值和最小值的索引
      var minBoxH = Math.min.apply(null, oBoxsH);
      var idx = getMinhIndex(oBoxsH, minBoxH);
          //计算及定义图片出现的位置
      oBoxs[i].style.position='absolute';
      oBoxs[i].style.left = oBoxs[idx].offsetLeft + 'px';
      oBoxs[i].style.top = minBoxH + 'px';
      // 改变数组值
      oBoxsH[idx] += oBoxs[i].offsetHeight;
    }
  }
}
// 取出所有class为clsName的元素
function getByClass(parent,clsName){
  var boxArr=new Array(), 
      oElements=parent.getElementsByTagName('*');
  for(var i=0;i<oElements.length;i++){
    if(oElements[i].className==clsName){
      boxArr.push(oElements[i]);
    }
  }
  return boxArr;
}

// 求值在数组中的索引,arr接收的是数组,val接收的是判断的值
function getMinhIndex(arr,val){
    for(var i=0; i<arr.length; i++) {
        if(arr[i] == val) {
            return i;
        }
    }
}

// 获取滚动时异步取数据的边界
function checkScrollSide () {
    var oBoxs = getByClass(document.getElementById("main"), "box");// 获取所有box
    var oEltHeight = Math.floor(oBoxs[oBoxs.length-1].offsetTop + oBoxs[oBoxs.length-1].offsetHeight/2);// 当滚动的高度大小最后一个元素一半时,加载数据
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;// 使用兼容代码
    return (oEltHeight < scrollTop + document.documentElement.clientHeight ? true : false)
}

绑定事件,加载数据

var imgData = [{"src":"30.jpg"},{"src":"31.jpg"},{"src":"32.jpg"},{"src":"33.jpg"},{"src":"34.jpg"}];
window.onload=function(){
     if(checkScrollSide()) {
        loadData();
    }
     waterfall('main','box');
     
    window.onscroll = function() {
        if(checkScrollSide()) {
            loadData();
            waterfall('main','box');
        }
    }
}

源代码以及素材下载地址

Github瀑布流工程源代码:https://github.com/sunhaikuo/waterfall.git

原文地址:https://www.cnblogs.com/sunhk/p/4304003.html