多种方式实现web瀑布流布局
2017-01-08 本文已影响11245人
oldSix_Zhu
据说是蘑菇街的web端面试题:"用至少两种方式实现瀑布流布局?"
其实百度一查有很多种方式.我整理三种:CSS,JS,jQuery,望温故而知新.
不一定是最好的,但是注释很详细,有点基础的肯定能看懂.
效果是这样的,上滑加载更多图片(假数据):
ps:能认出来这些图来源的握个爪,擦擦眼泪,不解释...

1:JavaScript
.html文件(三种方式都相同,就是内容,没啥说的):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>瀑布流首页</title>
<link href="css/index.css" rel="stylesheet">
</head>
<body>
<!--父盒子-->
<div id="main">
<!--单个盒子-->
<div class="box">
<!--图片盒子-->
<div class="pic">
<img src="images/1.jpg"/>
</div>
</div>
<!--单个盒子标签复制20次...图片名字改改...-->
</div>
<!--jQuery方式需要引入jQuery库,JS方式与CSS方式都要注释掉-->
<script src="js/jquery-3.1.1.min.js" type="text/javascript"></script>
<!--引入JS,CSS方式注释掉-->
<script src="js/index.js" type="text/javascript"></script>
</body>
</html>
.css文件(JS方式与jQuery方式相同,CSS方式肯定要改):
*{
/*去除边距*/
margin:0;
padding: 0;
/*html性能优化:虚拟dom,如果一个html标签没有设置css样式,就是虚拟的,
所以无论设置多少层div都对性能没有影响*/
}
#main{
/*定位*/
position: relative;
}
.box{
/*内边距*/
padding:15px 0 0 15px ;
float: left;
}
.pic{
/*边框*/
border:1px solid #dddddd;
}
.pic img{
width: 165px;
}
.js文件:
/**
* Created by Mac on 2017/1/7.
*/
function $(id) {
//判断id的类型
return typeof id === 'string'?document.getElementById(id):id;
}
//当网页加载完毕
window.onload = function () {
//瀑布流布局 保证传的参数能够找到父盒子
waterFall('main','box');
//滚动加载盒子
window.onscroll = function ()
{
//判断是否加载
if (checkWillLoad())
{
//创造假数据
var data = {'dataImg':[{'img':'23.jpg'},{'img':'24.jpg'},{'img':'25.jpg'},{'img':'26.jpg'},{'img':'27.jpg'},{'img':'28.jpg'}]};
//加载数据
for(var i=0; i<data.dataImg.length; i++)
{
//创建最外面的盒子
var newBox = document.createElement('div');
newBox.className = 'box';
$('main').appendChild(newBox);
//创建单个盒子
var newPic = document.createElement('div');
newPic.className = 'pic';
newBox.appendChild(newPic);
//创建img
var newImg = document.createElement('img');
newImg.src = 'images/' + data.dataImg[i].img;
newPic.appendChild(newImg);
}
//把刚创建的盒子瀑布流布局
waterFall('main','box');
}
}
}
//实现瀑布流布局
//规则:从第二行开始的图片,总是拼接在上一行高度最矮的图片后面
function waterFall(parent,box) {
//父盒子居中
//通过父盒子拿到所有的子盒子
var allBox = $(parent).getElementsByClassName(box);
//求出盒子的宽度
var boxWidth = allBox[0].offsetWidth;
//求出浏览器的宽度(包括边框的宽高)
var screenWidtn = document.body.offsetWidth;
//求出列数 //取整函数取整
var cols = Math.floor( screenWidtn/boxWidth);
//父标签居中
//先求出父标签宽度
$(parent).style.width = boxWidth * cols + 'px';
//居中
$(parent).style.margin = '0 auto';
//子盒子定位
//创建一个高度数组,存所有的高度
var heightArr = [];
//遍历
for(var i = 0; i < allBox.length ;i++)
{
//求出每个盒子的高度
var boxHeight = allBox[i].offsetHeight;
//第一行的盒子不需要重新定位//每一行的盒子数与列数相同
if(i<cols)
{
//添加第一行所有盒子高度
heightArr.push(boxHeight);
}
else//剩下的盒子都需要瀑布流布局
{
//求出最矮的盒子高度
var minBoxHeight = Math.min.apply(this,heightArr);
//求出最矮盒子对应的索引
var minBoxIndex = getMinBoxIndex(minBoxHeight,heightArr);
//盒子瀑布流定位 顶部间距就是最矮盒子的高度
allBox[i].style.position = 'absolute';
allBox[i].style.top = minBoxHeight + 'px';
allBox[i].style.left = minBoxIndex * boxWidth +'px';
//关键:更新数组最矮高度,使下一个图片在高度数组中总是找最矮高度的图片下面拼接
heightArr[minBoxIndex] += boxHeight;
}
}
}
//求出最矮盒子对应的索引函数
function getMinBoxIndex(val,arr) {
for(var i in arr)
{
if(val == arr[i])
{
return i;
}
}
}
//加载更多规则:当浏览器最下方到达图片的高度一半时让其刷新出来
//判断是否符合加载条件
function checkWillLoad() {
//取出所有盒子
var allBox = $('main').getElementsByClassName('box');
//取出最后一个盒子
var lastBox = allBox[allBox.length - 1];
//求出最后一个盒子高度的一半 + 内容与浏览器头部的偏离位置
var lastBoxDis = lastBox.offsetHeight * 0.5 + lastBox.offsetTop;
//求出浏览器的高度
// 注意:JS代码存在浏览器兼容问题 一般分标准模式(按屏幕算document.body.offsetHeight)和混杂模式(按所有内容算)
var screenHeight = document.documentElement.clientHeight;
//页面偏离屏幕的高度
var scrollTopHeight = document.body.scrollTop;
//判断
return lastBoxDis <= screenHeight + scrollTopHeight;
}
2:jQuery方式的.js文件:
jQuery的API中文文档:http://jquery.cuishifeng.cn/index.html
简单介绍一下jQuery:
JS存在的问题:
1:浏览器兼容问题
2:JS存在复杂的dom操作,实现特效动画复杂
3:请求网络数据存在跨域问题,跨域问题就是自动做代码保护,不允许跨域调用其他页面的对象,
类似中国的墙'长城',即只能访问当前服务器的网址,无法访问外界的网址,解决方法百度上很多,
但一般是后台处理,我并没有做过,所以就不细写了
jQuery优势:
1.几乎不存在浏览器兼容问题
2.轻松实现dom操作,特效,动画
3.多种方式的网络请求方案
// document.write("<script src='jquery-3.1.1.min.js'></script>");
//当页面加载完毕
$(window).on('load',function () {
//1.实现瀑布流布局
waterFall();
//2.滚动加载
$(window).on('scroll',function () {
//判断是否加载
if (checkWillLoad())
{
////创造假数据
var data = {'dataImg':[{'img':'23.jpg'},{'img':'24.jpg'},{'img':'25.jpg'},{'img':'26.jpg'},{'img':'27.jpg'},{'img':'28.jpg'}]};
//遍历创建盒子
$.each(data.dataImg,function (index,value)
{
//创建一个div标签 设置它的类为'box' 添加到'main'里面去
var newBox = $('<div>').addClass('box').appendTo($('#main'));
var newPic = $('<div>').addClass('pic').appendTo($(newBox));
//创建img 取出遍历的对象value的img属性对应的值
$('<img>').attr('src','images/'+$(value).attr('img')).appendTo($(newPic));
})
//1.实现瀑布流布局
waterFall();
}
});
});
//实现瀑布流布局
function waterFall () {
//拿到所有的盒子
var allBox = $('#main > .box');
//取出其中一个盒子的宽度
var boxWidth = $(allBox).eq(0).outerWidth();
//取出屏幕的高度
var screenWidth = $(window).width();
//求出列数 //取整函数取整
var cols = Math.floor( screenWidth/boxWidth);
//父标签居中
$('#main').css({
'width':cols * boxWidth + 'px',
'margin':'0 auto'
});
//对子盒子定位
var heightArr = [];
//遍历
$.each(allBox,function (index,value) {
//取出单独盒子的高度
var boxHeight = $(value).outerHeight();
//判断是否第一行
if(index < cols)
{
heightArr[index] = boxHeight;
}
else //剩余的盒子要瀑布流布局
{
//求出最矮的盒子高度
var minBoxHeight = Math.min.apply(null,heightArr);
//取出最矮高度对应的索引 封装了js的这个方法
var minBoxIndex = $.inArray(minBoxHeight,heightArr);
//定位
$(value).css({
'position':'absolute',
'top':minBoxHeight + 'px',
'left':minBoxIndex * boxWidth + 'px'
});
//更新数组中最矮的高度
heightArr[minBoxIndex] += boxHeight;
}
})
}
//判断是否符合加载条件
function checkWillLoad() {
//直接取出最后一个盒子
var lastBox = $('#main > div').last();
//取出最后一个盒子高度的一半 + 头部偏离的位置
var lastBoxDis = $(lastBox).outerHeight() + $(lastBox).offset().top;
//求出浏览器的高度
var clientHeight = $(window).height();
//求出页面偏离浏览器高度
var scrollTopHeight = $(window).scrollTop();
//比较返回
return lastBoxDis <= clientHeight + scrollTopHeight;
}
3:CSS方式修改一下.css中的内容即可:
主要是利用了css3中增加了一个新的属性:column
具体看看这个很详细了:http://www.tuicool.com/articles/RvY3Yv
#main{
/*定位*/
/*position: relative;*/
/*多栏布局 设置栏宽度*/
-webkit-column-width:202px;
-moz-column-width:202px;
column-width:202px;
}