javascript ·

解析瀑布流布局实现原理

说瀑布流原理其实很简单,原理就是哪列高度和小就将元素放到哪列。那么这就涉及到一个算法了,就是给定一个数组,分成N组,使得这N组的每组和之差最小。

基本算法

下面我们先来说一下这个思路,我们首先应该想到的就是使用递归算法来实现。递归函数的参数应该包含源数组、组数和目标数组(目标数组是一个二维数组)。

function minHeightDifference(arr,groupCount,tarrgetArr){
//doSomething
}

在方法中每次取出源数组的第一个值,然后判断目标数组这个二维数组中哪个数组的和最小,就将该值push到其中,下面我们来看一下简单的实现步骤

if(!Array.prototype.watherFullSum){
    Array.prototype.watherFullSum = function(){
        var temp = 0;
        for(var i=0;i<this.length;i++){
            if(!isNaN(this[i])){
                temp+=this[i];
            }
        }
        return temp;
    }
}

function minHeightDifference(arr,groupCount,tarrgetArr){
    if(arr.length==0){//判断源数组是否为空
        return tarrgetArr
    }
    var groupArr =[];
    if(!tarrgetArr){
        groupArr = Array.apply(null,new Array(groupCount)).map((item)=>0)
        //初始调用无需填写目标数组,创建一个长度为groupCount的全为0的空数组
    }else{
        groupArr = tarrgetArr
    }


    var tempArr =[];
    for(var i=0;i<groupArr.length;i++){
        tempArr[i] = groupArr[i] instanceof Array ? groupArr[i].watherFullSum():0
    }
    //查找最小高度是哪列
    var min = Math.min.apply(null,tempArr);
    var minIndex = tempArr.indexOf(min);
    //如果不是数组的话,则生成一个空数组
    if(!(groupArr[minIndex] instanceof Array)){
        groupArr[minIndex] = [];
    }
    groupArr[minIndex].push(arr[0]);

    return minHeightDifference(arr.slice(1),groupCount,groupArr)
}

上面的代码及注释很清晰,不在额外赘述,调用的时候就很简单了

minHeightDifference([1,2,3,4,2,3,4,5,1,2,3,4,2,3,1,5,2,7],4)

实现瀑布流功能

对于实现瀑布流功能的话,我们只需要构成一个传入的数组即可,数组内容为元素的高度,但是为了方便操作元素位置,我们需要对这个数组进行一下改造

var x = [{dom:obj,height:height}]

改造成上述代码格式,那么上面的算法代码也需要进行相应的修改:

if(!Array.prototype.watherFullSum){
    Array.prototype.watherFullSum = function(){
        var temp = 0;
        for(var i=0;i<this.length;i++){
            if(!isNaN(this[i].height)){
                temp+=this[i].height;
            }
        }
        return temp;
    }
}

function minHeightDifference(arr,groupCount,tarrgetArr){
    if(arr.length==0){
        return tarrgetArr
    }
    var groupArr =[];
    if(!tarrgetArr){
        groupArr = Array.apply(null,new Array(groupCount)).map((item)=>0)
    }else{
        groupArr = tarrgetArr
    }


    var tempArr =[];
    for(var i=0;i<groupArr.length;i++){
    tempArr[i] = groupArr[i] instanceof Array ? groupArr[i].watherFullSum():0
    }
    var tempHeightArr = !isNaN(tempArr[0])?tempArr:tempArr.map(item=>item.height)
    var min = Math.min.apply(null,tempHeightArr);

    var minIndex = tempHeightArr.indexOf(min);
    if(!(groupArr[minIndex] instanceof Array)){
        groupArr[minIndex] = [];
    }
    groupArr[minIndex].push(arr[0]);

    return minHeightDifference(arr.slice(1),groupCount,groupArr)
}

调用就很简单了:

var xms = [];
Array.from(document.querySelectorAll("#test>div")).map(item=>{
    xms.push({'dom':item,'height':item.offsetHeight});
})

var result = minHeightDifference(xms,4);
var x = ''
var maxIndex = Math.max.apply(null,result.map(item=>item.length));
for(var i=0;i<maxIndex;i++){
    result.map((item,key)=>{
        if(item[i]){

        item[i].dom.style.top = item.slice(0,i).watherFullSum();
        item[i].dom.style.left = item[i].dom.offsetWidth*key;
        }
    })
}

我们的html结构是这样的

<html>
<head>
<title>瀑布流</title>
<style>
#test div{
border:1px solid #000;
    display:inline-block;
    position:absolute;
    width:100px;
    box-sizing:border-box;
}
#test{
    width:450px;
    position:relative;
}

</style>
</head>

<body>
<div id="test" >
    <div style="height:83px">1</div>
    <div style="height:103px">2</div>
    <div style="height:84px">3</div>
    <div style="height:56px">4</div>
    <div style="height:78px">5</div>
    <div style="height:93px">6</div>
</div>
</body>
</html>

上面的html结构我省略了一部分,后面的div个数和随意增加,其实现效果如下图
解析瀑布流布局实现原理

到此,基本上实现了瀑布流的效果,具体精细效果请各位自行添加即可。

参与评论