瀑布流布局

zhangxinxu博客的写法,传统js写法css

var waterFall = {
        container: document.getElementById("container"), //瀑布流容器元素
        columnNumber: 1, //瀑布流有多少列
        columnWidth: 210, //每一列的宽度
        // P_001.jpg ~ P_160.jpg
        rootImage: "http://cued.xunlei.com/demos/publ/img/", //图片路径
        indexImage: 0, //图片序号
        
        scrollTop: document.documentElement.scrollTop || document.body.scrollTop, //页面滚动距离
        detectLeft: 0,
        
        loadFinish: false, //是否加载完全部图片了
        
        // 返回固定格式的图片名
        getIndex: function() {
            var index = this.indexImage;
            if (index < 10) {
                index = "00" + index;    
            } else if (index < 100) {
                index = "0" + index;    
            }
            return index;
        },
        
        // 是否滚动载入的检测,若是页面滚动超过某一列的内容,就对这一列执行append方法
        appendDetect: function() {
            var start = 0;
            for (start; start < this.columnNumber; start++) {
                var eleColumn = document.getElementById("waterFallColumn_" + start);
                if (eleColumn && !this.loadFinish) {
                    if (eleColumn.offsetTop + eleColumn.clientHeight < this.scrollTop + (window.innerHeight || document.documentElement.clientHeight)) {
                        this.append(eleColumn);
                    }
                }            
            }
            
            return this;
        },
        
        // 滚动载入
        append: function(column) {
            this.indexImage += 1;
            var html = '', index = this.getIndex(), imgUrl = this.rootImage + "P_" + index + ".jpg";
            
            // 图片尺寸
            var aEle = document.createElement("a");
            aEle.href = "###";
            aEle.className = "pic_a";
            aEle.innerHTML = '<img src="'+ imgUrl +'" /><strong>'+ index +'</strong>';
            column.appendChild(aEle);
            
            if (index >= 160) {
                //alert("图片加载光光了!");
                this.loadFinish = true;
            }
            
            return this;
        },
        
        // 页面加载初始建立
        create: function() {
            this.columnNumber = Math.floor(document.body.clientWidth / this.columnWidth); //根据body宽度和一列的宽度计算出有多少列
            
            var start = 0, htmlColumn = '', self = this;
            for (start; start < this.columnNumber; start+=1) {
                htmlColumn = htmlColumn + '<span id="waterFallColumn_'+ start +'" class="column" style="width:'+ this.columnWidth +'px;">'+ 
                    function() {
                        var html = '', i = 0;
                        for (i=0; i<5; i+=1) {
                            self.indexImage = start + self.columnNumber * i;
                            var index = self.getIndex();
                            html = html + '<a href="###" class="pic_a"><img src="'+ self.rootImage + "P_" + index +'.jpg" /><strong>'+ index +'</strong></a>';
                        }
                        return html;    
                    }() +
                '</span> '; //循环建立每一列,每一列初始化就先填入5张图片   
            }
            htmlColumn += '<span id="waterFallDetect" class="column" style="width:'+ this.columnWidth +'px;"></span>'; //这个块用于检测是否页面的宽度发生变化,是否须要触发refresh操做
            
            this.container.innerHTML = htmlColumn;
            
            this.detectLeft = document.getElementById("waterFallDetect").offsetLeft;
            return this;
        },
        
        refresh: function() {
            var arrHtml = [], arrTemp = [], htmlAll = '', start = 0, maxLength = 0;
            for (start; start < this.columnNumber; start+=1) {
                var arrColumn = document.getElementById("waterFallColumn_" + start).innerHTML.match(/<a(?:.|\n|\r|\s)*?a>/gi);
                if (arrColumn) {
                    maxLength = Math.max(maxLength, arrColumn.length);
                    // arrTemp是一个二维数组
                    arrTemp.push(arrColumn);
                }
            } //布局从新变化的时候先把全部已经加载好的图片按照列存在二维数组里
            
            // 须要从新排序 二维数组从左到右,从上到下,把分散在各个列里的图片块再次按照顺序连成一个数组
            var lengthStart, arrStart;
            for (lengthStart = 0; lengthStart<maxLength; lengthStart++) {
                for (arrStart = 0; arrStart<this.columnNumber; arrStart++) {
                    if (arrTemp[arrStart][lengthStart]) {
                        arrHtml.push(arrTemp[arrStart][lengthStart]);    
                    }
                }    
            }
            
            
            if (arrHtml && arrHtml.length !== 0) {
                // 新栏个数        
                this.columnNumber = Math.floor(document.body.clientWidth / this.columnWidth);
                
                // 计算每列的行数
                // 向下取整
                var line = Math.floor(arrHtml.length / this.columnNumber);
                
                // 从新组装HTML
                var newStart = 0, htmlColumn = '', self = this;
                for (newStart; newStart < this.columnNumber; newStart+=1) {
                    htmlColumn = htmlColumn + '<span id="waterFallColumn_'+ newStart +'" class="column" style="width:'+ this.columnWidth +'px;">'+ 
                        function() {
                            var html = '', i = 0;
                            for (i=0; i<line; i+=1) {
                                html += arrHtml[newStart + self.columnNumber * i];
                            }
                            // 是否补足余数
                            html = html + (arrHtml[newStart + self.columnNumber * line] || '');
                            
                            return html;    
                        }() +
                    '</span> ';    
                }
                htmlColumn += '<span id="waterFallDetect" class="column" style="width:'+ this.columnWidth +'px;"></span>';
            
                this.container.innerHTML = htmlColumn;
                
                this.detectLeft = document.getElementById("waterFallDetect").offsetLeft;
                
                // 检测
                this.appendDetect();
            }
            return this;
        },
        
        // 滚动加载
        scroll: function() {
            var self = this;
            window.onscroll = function() {
                // 为提升性能,滚动先后距离大于100像素再处理
                var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                if (!this.loadFinish && Math.abs(scrollTop - self.scrollTop) > 100) {
                    self.scrollTop = scrollTop;
                    self.appendDetect();    
                }
                
            };
            return this;
        },
        
        // 浏览器窗口大小变换
        resize: function() {
            var self = this;
            window.onresize = function() {
                var eleDetect = document.getElementById("waterFallDetect"), detectLeft = eleDetect && eleDetect.offsetLeft;
                if (detectLeft && Math.abs(detectLeft - self.detectLeft) > 50) {
                    // 检测标签偏移异常,认为布局要改变
                    self.refresh();    
                }
            };
            return this;
        },
        init: function() {
            if (this.container) {
                this.create().scroll().resize();    
            }
        }
    };
    waterFall.init();    

其余方法html

Multi-columns多列布局数组

html:浏览器

<div class="masonry"> 
    <div class="item"> 
        <div class="item__content"> </div> 
    </div> 
    <div class="item"> 
        <div class="item__content"> </div>  
    </div> 
    <!-- more items --> 
</div>

css:app

.masonry { column-count: 5; column-gap: 0; }

瀑布流容器分红5列,列与列之间的间距是0。ide

使用多列布局的关键在于内容的中断(break),中断有三种,page-break,column-break,region-break。布局

为了阻止内容的中断,避免内容的一部分被截断到了下一列,这里必须使用break-inside。性能

.item { break-inside: avoid; box-sizing: border-box; padding: 10px; }

设置break-indide:avoid;后,每个item元素都能完整显示,内容不会再被截断致使跨列了。flex

借助媒体查询,在不一样宽度页面状况下,列数不一样:this

.masonry { 
    column-count: 1; // one column on mobile 
} 
@media (min-width: 400px) { 
    .masonry { 
        column-count: 2; // two columns on larger phones 
    } 
} 
@media (min-width: 1200px) { 
    .masonry { 
        column-count: 3; // three columns on...you get it 
    } 
} 
<!-- etc. -->

这样就使用多列布局实现了瀑布流,纯css实现。

效果请看codepen

flexbox弹性盒布局

html:

<div class="masonry">
    <div class="column">
        <div class="item">
          <div class="item__content">
          </div>
        </div>
        <!-- more items -->
    </div>
    <div class="column">
        <div class="item">
          <div class="item__content">
          </div>
        </div>
        <!-- more items -->
    </div>
    <div class="column">
        <div class="item">
          <div class="item__content">
          </div>
        </div>
        <!-- more items -->
    </div>
</div>

css:

.masonry {
    display: flex;
    flex-direction: row;
}

.column {
    display: flex;
    flex-direction: column;
    width: calc(100%/3);
}

将masonry盒子和column盒子都设置为flex,masonry的方向设置为行,而column设置为列。

每一列的宽度经过calc()来计算。

还须要媒体查询来控制不一样宽度页面的效果:

.masonry {
    display: flex;
    flex-direction: column;
}

@media only screen and (min-width: 500px) {
    .masonry {
        flex-direction: row;
    }
}

.column {
    display: flex;
    flex-flow: column wrap;
    width: 100%;
}

@media only screen and (min-width: 500px) {
    .column {
        width: calc(100%/5);
    }
}

当页面宽度小于500px的时候,masonry盒子方向变为列,所有变成一列显示;当页面宽度大于500px的时候,masonry盒子方向变为行,一行中的每一列的宽度是calc(100%/5),变成5列显示。

实际效果:

效果请看这里

相关文章
相关标签/搜索