ウォーターフォールフローレイアウトのjQuery実装を詳しく解説(PC・モバイル)_jquery

WBOY
リリース: 2016-05-16 15:34:30
オリジナル
1344 人が閲覧しました

ウォーターフォール フロー レイアウトは、PC 上でも携帯電話などのモバイル デバイス上でも、現在画像を表示する非常に一般的な方法となっています。レイアウト図には大きく分けて「等高・等幅」、「等幅・不等高」、「等高・不等幅」の3種類があります。次に、最も一般的な等幅・不等高を例に説明します。

例として Baidu の写真を使用します:

これは PC での一般的なウォーターフォール フローのレイアウト方法です。次に、Baidu の画像で要素がどのようにレイアウトされているかを確認してみましょう。

ご覧のとおり、実際には複数の等しい幅の列コンテナーが含まれており、画像は計算によって異なるコンテナーにプッシュされます。この記事で紹介する表示方法は位置決めによるものですが、最終的なレイアウトの表示方法は異なりますが、以前のアルゴリズムは比較的似ています。

実践

まず、次のスタイルのいくつかのユニットを本文に書き込み、「ボックス」を左側にフローティングします。

<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. まず、ブラウザーで 1 行に収容できる画像の数 (num) を計算します。ここで true が渡される場合、要素のすべてのボックス モデル属性 (margin、padding) のサイズが使用されます。 、境界線が返されます

2. 各列の高さを格納する配列 (columnHeightArr) を作成します。配列の長さは

です。

3. すべての画像をスキャンし、最初の行の画像の高さを列の高さの配列 (columnHeightArr) に保存します。最初に、最小の高さ (minHeight) とすべての列の最小の高さを計算します。 (minHeightIndex)。次に、列の下の 2 行目から始まる画像を最小の高さで配置します。効果は次のようになります:

写真は正しい場所に配置されていますが、すべての写真が同じ場所に配置されていることがわかります。これは、写真を配置した後に列の高さを増やす必要があるためです。

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 に変換して渡します。

* 次に、非常に実用的なちょっとしたトリック を紹介します。これにより、要素のサイズがどのように変化しても 確実に比率が変化します。常に一貫性を保ちます 。要素は応答性を高めるためにパーセンテージを使用することが多いため、この手法はモバイルで特に効果的です。

携帯電話のページに画像がある場合、その幅は画面の半分、アスペクト比はどの解像度の携帯電話でも変わらない必要があります。やり方は?次の属性を要素に設定します:

.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瀑布流布局,内容很丰富,需要大家一点点的理解消化,真正的做到学以致用,希望能够帮助到大家。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート