首先我们将如下样式的若干个单元写进body中,并将“box”向左浮动:

<div class="box">
 <img class="img" src="./resource/images/1.jpg" />
 <div class="desc">Description</div>
</div>
<div class="box">
 <img class="img" src="./resource/images/2.jpg" />
 <div class="desc">Description</div>
</div>
<div class="box">
 <img class="img" src="./resource/images/3.jpg" />
 <div class="desc">Description</div>
</div>
接下来:
var boxArr = $('.box'),
  num = Math.floor(document.body.clientWidth / boxArr.eq(0).outerWidth(true)),
 columnHeightArr = [];
columnHeightArr.length = num;
boxArr.each(function(index, item) {
 if (index < num) {
 columnHeightArr[index] = $(item).outerHeight(true);
 } else {
 var minHeight = Math.min.apply(null, columnHeightArr),
 minHeightIndex = $.inArray(minHeight,columnHeightArr);
 
 $(item).css({
 position: 'absolute',
 top: minHeight,
 left: boxArr.eq(minHeightIndex).position().left
 });
 }
});

以上代码大意为:

1. 首先计算出在浏览器中一行能容纳多少图片 (num) ,注意这里用了outerWidth,当传入true时会返回元素包括margin、padding、border全部盒模型属性的尺寸;

2. 创建一个存储每一列高度的数组 (columnHeightArr) ,该数组的长度即为num值;

3. 遍历所有图片,将第一行的图片高度分别存入列高数组中 (columnHeightArr) ,从第二行开始,首先计算出所有列中最小的高度 (minHeight) 以及最小高度所在的列 (minHeightIndex)。之后将第二行开始的图片定位在高度最小列的下面,效果如下:

可以看到虽然摆对了地方但是所有的图片都放在同一个地方了,这是因为我们需要在摆放一张图片后就要增加该列的高度:

var boxArr = $('.box'),
 num = Math.floor(document.body.clientWidth / boxArr.eq(0).outerWidth(true)),
 columnHeightArr = [];
columnHeightArr.length = num;
 
boxArr.each(function(index, item) {
  if (index < num) {
    columnHeightArr[index] = $(item).outerHeight(true);
  } else {
    var minHeight = Math.min.apply(null, columnHeightArr),
 minHeightIndex = $.inArray(minHeight, columnHeightArr);
 
    $(item).css({
   position: 'absolute',
   top: minHeight,
   left: boxArr.eq(minHeightIndex).position().left
 });
 
    columnHeightArr[minHeightIndex] += $(item).outerHeight(true);
  }
});

注意:上面的代码需要运行于window.onload方法里,因为只有当页面中的图片资源全部加载完毕后,其每张图片的高度才会有效。

因此会有一些很严重的问题,当网络不好的时候图片没有完全加载完成就会出现图片展示不全高度缺失的情况,这点在移动端很明显。而且当我们加载更多时,更难判断新追加的图片是否加载完成。

在实际生产中更不会有一开始就将图片写死在HTML中的情况,所以我们通常用以下的方式来做:

首先我们在获得图片地址时同时也需要获取图片的宽和高 ,这点对服务端后台来说并不是什么难事,可以拜托后台兄弟将图片的宽高数据拼进JSON,传递给你;

*接下来介绍小技巧,非常实用,它能保证一个元素无论大小如何变化,比例始终保持一致。这个技巧尤其适用于移动端,因为元素为了响应式通常使用百分比的形式。

假如手机页面中有一张图片,其宽度要为屏幕的一半,高宽比为2:1,需要在任何分辨的手机上保持比例不变。如何做?给元素设置如下属性:

.box {
 width: 50%;
 height: 0;
 padding-bottom: 100%;
}

不设置高度,而是用padding“挤”出元素高度,而padding的百分比值都是基于父级容器的宽度。padding需要挤多少呢?就是宽度乘以高宽比(width和padding值均为百分比值),这就是我们为什么需要获得图片尺寸的原因。

效果:

可以看到在chrome手机模拟器中ipone4和肾6Plus的显示效果是完全一样的。在手机页面中宽是固定的,而高会随着页面内容的多少而变化,这个技巧利用元素padding百分比的值其实是基于其父级容器的宽,将高的值巧妙的转化成与宽相关。

说到现在可能有人终于忍不住要问了,讲了这么多和瀑布流有什么关系!简单就是一句话,我们要抛弃 img 标签,而采用背景图的方式。为了使用背景图,就得保持元素的比例永远与图片保持一致。

通过这种方式,可以不用判断图片都加载完毕,直接产生一些与图片同比例的div,再为其设置背景图,如下:

这里比如最外层的box宽度为220px,里面的img元素宽度就可以为100%,高度就可以通过padding挤出了。

懒加载

使用背景图的方式还有好处那就是可以比较方便的实现懒加载。那什么是懒加载呢?就是当元素在我们的视野中时才展示图片,滚动时屏幕下方的图片并不展示,这可以很好的增加加载速度提升体验。

首先我们给最外层的box增加一个box-item类名(之后有用),将图片url并不设置给backgroundImage属性,而是赋给一个自定义属性:data-src

<div class="box box-item">
 <div class="img" data-src="./resource/images/1.jpg"></div>
 <div class="desc">Description</div>
</div>
接下来我们编写懒加载函数:
function lazyLoad() {
  var boxArr = $('.box-item');
  
  boxArr.each(function(index, item) {
    var viewTop = $(item).offset().top - $(window).scrollTop(),
 imgObj = $(item).find('.img');
 
 if ((viewTop < $(window).height()) && (($(item).offset().top + $(item).outerHeight(true)) > $(window).scrollTop())) {
   imgObj.css('backgroundImage','url('+imgObj.attr("data-src")+')').removeClass('data-src');
   $(item).removeClass('box-item');
 }
 })
}

首先我们获取所有拥有 .box-item 类名的元素,遍历。viewTop 为图片相对于浏览器窗口的相对高度,类似于position:fixed感觉。

通过条件进行判断,只有当该图片在浏览器窗口内(之上或之下都不行)时,将需要设置背景图元素的 data-src 值展示出来,并删除该属性。

之后将最外层元素的 box-item 删除,因为已经展示出来的图片不需要再进行这些判断,删除了该类名下一次滚动时就不会获取到已经展示过的元素,需要遍历的次数就会越来越少,这样能起到一个优化的作用。

该函数需要在你的元素已经append进页面时调用,以及在滚动时调用:

lazyLoad();
$(window).scroll(lazyLoad);

滚动加载

说完了懒加载,再说说滚动加载。所谓滚动加载就是当页面滚动到底部附近时加载新的图片。我这里选择的是滚动到高度最小的列底部时加载新的数据,你也可以根据自己的喜好来做判断。

function scrollLoad() {
  var viewHeight = $(window).scrollTop() + $(window).height(),
 minHeight = Math.min.apply(null, columnHeightArr);
 
  if (viewHeight >= minHeight) {
   //loadMore...
  }
}滚动加载也是在window的滚动事件中进行监听,可以与懒加载一起进行:
$(window).scroll(function() {
 scrollLoad();
 lazyLoad();
});
说完了PC端,我们来说下手机端。其实原理是一样的,只是从多列变成固定的两列了。
var boxArr = $('.box'),
 columnHeightArr = [];
columnHeightArr.length = 2;
 
boxArr.each(function(index, item) {
  if (index < 2) {
    columnHeightArr[index] = $(item).outerHeight(true);
  } else {
    var minHeight = Math.min.apply(null, columnHeightArr),
 minHeightIndex = $.inArray(minHeight, columnHeightArr);
 
    $(item).css({
   position: 'absolute',
   top: minHeight,
   left: boxArr.eq(minHeightIndex).position().left
 });
 
    columnHeightArr[minHeightIndex] += $(item).outerHeight(true);
  }
});
不同的是为了适应不同屏幕的手机,最外层的box容器宽度和边距要设置成百分比的形式。

最后有一点要注意,因为我们没有像百度一样用一个个列盒子去装,而是用定位的方式。导致的问题是图片元素的父级没法自适应高度,如果你有相关的需求我们可以计算出所有列中最长的长度,并将这个值赋值给父容器的min-height属性:

$('body').css('minHeight',Math.max.apply(null, columnHeightArr));

整理下完整的代码,瀑布流的全套服务就到这了

var dataArr = [
 {picUrl:'./resource/images/1.jpg',width:522,height:783},
 {picUrl:'./resource/images/2.jpg',width:550,height:786},
 {picUrl:'./resource/images/3.jpg',width:535,height:800},
 {picUrl:'./resource/images/4.jpg',width:578,height:504},
 {picUrl:'./resource/images/5.jpg',width:1440,height:900}
 ];
 
 $.each(dataArr, function(index, item) {
 $("body").append('<div class="box box-item">' +
  '<div class="img" style="height:0;padding-bottom:'+cRate(item) * 100 + "%"+'" data-src="'+item.picUrl+'"></div>' +
  '<div class="desc">Description</div>' +
  '</div>');
 });
 
 var boxArr = $('.box'),
 num = Math.floor(document.body.clientWidth / boxArr.eq(0).outerWidth(true)),
 columnHeightArr = [];
 columnHeightArr.length = num;
  
 arrangement();
 
  $('body').css('minHeight',Math.max.apply(null, columnHeightArr));
 
 lazyLoad();
 
 function arrangement() {
 boxArr.each(function(index, item) {
 if (index < num) {
 columnHeightArr[index] = $(item).outerHeight(true);
 } else {
 var minHeight = Math.min.apply(null, columnHeightArr),
  minHeightIndex = $.inArray(minHeight, columnHeightArr);
 $(item).css({
  position: 'absolute',
  top: minHeight,
  left: boxArr.eq(minHeightIndex).position().left
 });
 columnHeightArr[minHeightIndex] += $(item).outerHeight(true);
 }
 });
 }
 
 function lazyLoad() {
 var boxArr = $('.box-item');
 boxArr.each(function(index, item) {
 var viewTop = $(item).offset().top - $(window).scrollTop(),
 imgObj = $(item).find('.img');
 if ((viewTop < $(window).height()) && ($(item).offset().top + $(item).outerHeight(true) > $(window).scrollTop())) {
// console.log($(item).attr('data-src'));
 imgObj.css('backgroundImage','url('+imgObj.attr("data-src")+')').removeClass('data-src');
 $(item).removeClass('box-item');
 }
 })
 }
 
 function cRate(obj) {
 return obj.height / obj.width;
 }
 
 function scrollLoad() {
 var viewHeight = $(window).scrollTop() + $(window).height(),
 minHeight = Math.min.apply(null, columnHeightArr);
 if (viewHeight >= minHeight) {
 //loadMore...
 }
 }
 
 $(window).scroll(function() {
 lazyLoad();
 scrollLoad();

 }};

jQuery实现瀑布流布局详解(PC和移动端)的更多相关文章

  1. jQuery Validate验证框架详解

    转自:http://www.cnblogs.com/linjiqin/p/3431835.html jQuery校验官网地址:http://bassistance.de/jquery-plugins/ ...

  2. jQuery的deferred对象详解

    jQuery的deferred对象详解请猛击下面的链接 http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_ ...

  3. jQuery的deferred对象详解(转载)

    本文转载自: jQuery的deferred对象详解(转载)

  4. 触碰jQuery:AJAX异步详解

    触碰jQuery:AJAX异步详解 传送门:异步编程系列目录…… 示例源码:触碰jQuery:AJAX异步详解.rar AJAX 全称 Asynchronous JavaScript and XML( ...

  5. jQuery调用AJAX异步详解[转]

    AJAX 全称 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML).它并非一种新的技术,而是以下几种原有技术的结合体. 1)   使用CSS和X ...

  6. jQuery的deferred对象详解(一)

    最近一段时间,都在研究jquery里面的$.Deffered对象,几天都搞不明白,其中源码的运行机制,网上查找了相关的资料,<jQuery的deferred对象详解>阮一峰老师的文章,里面 ...

  7. 触碰jQuery:AJAX异步详解(转)

    AJAX 全称 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML).它并非一种新的技术,而是以下几种原有技术的结合体. 1)   使用CSS和X ...

  8. 【转】jQuery Validate验证框架详解

    jQuery校验官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation 一.导入js库 <script type=& ...

  9. jQuery form插件使用详解

    点击打开: jquery选择器全解 jquery中的style样式操作 jquery中的DOM操作 jquery中的事件操作全解 jquery中的动画操作全解 jquery中ajax的应用 自定义jq ...

随机推荐

  1. jsp标签(jsp动作元素)

    <jsp:forward page=”/index.jsp”></jsp:forward>也是跳转. 可以用来配置为首页,来启动某个servlet. <jsp:inclu ...

  2. 【JS】jQuery设置定时器,访问服务器(PHP示例)配合微信、支付宝原生支付,跳转web网页

    废话不多说,直接上代码: 把下面的js放在html的</body>即可 <!-- 设置页面定时器,3秒查询一次数据库该订单状态,ok就跳走 --xzz1115> <scr ...

  3. xtrabackup备份方式搭建一个mysql slave

    以前mysql搭建新备库都是在现在业务较小的备库上停止同步或停止数据库,然后拷贝数据库到新备库,配置好新备库后,再开启同步或数据库.然而,这次没有空闲备库用来搭新备库.需要从一个业务繁忙的数据库中搭建 ...

  4. WebService一些概念

    1.WebService,顾名思义就是基于Web的服务.它使用Web(HTTP)方式,接收和响应外部系统的某种请求.从而实现远程调用. 2.我们可以调用互联网上查询天气信息Web服务,然后将它嵌入到我 ...

  5. Android中将一个图片切割成多个图片[转]

    有种场景,我们想将一个图片切割成多个图片.比如我们在开发一个拼图的游戏,就首先要对图片进行切割. 以下是封装好的两个类,可以实现图片的切割.仅供参考和学习. 一个是ImagePiece类,此类保存了一 ...

  6. C++求两个数的最大值

    //不使用if,:?等推断语句.求两个数字中最大的那个数字. #include<iostream> using namespace std; int main() { int a = -1 ...

  7. 利用国内的源安装 Python第三方库

    我们需要安装一些Python的第三方库,但是使用  pip install + 第三方库  的时候,会出现下载速度慢的问题,当然我们也可以使用国内的源安装. 例如: sudo pip install ...

  8. django.db.utils.OperationalError: no such table: auth_user

    关于使用django 首次创建超级管理员时,出现     django.db.utils.OperationalError: no such table: auth_user   错误 1.首先使用命 ...

  9. MySQL防止delete命令删除数据

    在sql中删除数据库中记录我们会使用到delete命令,这样如果不小心给删除了很难恢复了,总结一些删除数据但是不在数据库删除的方法. 方法一 我常用的做法,就是在数据库中加一个删除标识字段,如: is ...

  10. [svc]执行sudo时报错:effective uid is not 0

    http://jingyan.baidu.com/article/c45ad29cd83d4b051753e232.html 今天将 / 授权给了一个普通用户 导致一些问题. 启事: 操作前一定要先在 ...