滝の流れは数年前から人気があったはずです。最初は Pinterest によって引き起こされた波でしたが、その後、国内のデザインが急成長し、Mogujie、Mark's (ただし、最近ではポルノに関与しており、からかわれているようです)、これらはすべて素晴らしい例ですが、今日は滝の流れについて話します。
1. 絶対レイアウト:
JS 実装原理
実際、ウォーターフォール スタイルの主な難しさは、対応する列に画像をきちんと配置する方法と、画像の更新と読み込みをいつ開始するかです。
画像をきちんと配置するための主なロジックとアルゴリズムは、まずコンテナー内に配置できる列の数を取得し、次に計算によって最初の列の高さを保存し、次に残りの高さをトラバースします (コンテナ内の要素を除く)。最初の列) を選択し、それぞれ最も高さの低い列を入力します。 1 つずつ追加して、最後にトラバースを終了します。
更新を開始するための設定は非常に簡単です。ウォーターフォール更新は、window.onscroll という 1 つのイベントにのみ関連します。主なアルゴリズムは、ページが最も低い高さまでスライドすると、ノードの読み込みと追加を開始することです。もちろん、追加されるノードの数は固定されていません。
まずはコードから説明していきます。1つは画像の配置、もう1つはレスポンシブ読み込みの設定です。
1.写真の配置
var $ = function() { return document.querySelectorAll.apply(document, arguments); } var arrHeight = []; //得到分列的高度 var columns = function() { //计算页面最多可以放多少列 var containerW = $("#main")[0].clientWidth, pinW = $(".pin")[0].offsetWidth; return Math.floor(containerW / pinW); } var getIndex = function(arr) { //获得最小高度的index var minHeight = Math.min.apply(null, arr); //获得最小高度 for (var i in arr) { if (arr[i] === minHeight) { return i; } } } //根据列数确定第一排img的高度并放入数组当中。 var setCenter = (function() { //通过列数设置宽度 var main = $('#main')[0]; //获得罩层 var getPadding = function() { //设置padding var col = columns(); //获得最后一列 var padding = main.clientWidth - col * $('.pin')[0].offsetWidth; return padding / 2; } var getComputedStyle = function(ele) { //兼容IE的支持情况 if (window.getComputedStyle) { return window.getComputedStyle(ele); } else { return ele.currentStyle; } } var getPinPad = function() { //获得pin的padding值 var pin = $(".pin")[0]; return parseInt(getComputedStyle(pin).paddingLeft); } return function() { //设置宽度 main.style.padding = `0 ${getPadding()}px 0 ${getPadding()-getPinPad()}px`; } })(); var overLoad = function(ele) { var index = getIndex(arrHeight), minHeight = Math.min.apply(null, arrHeight), //获取最小高度 pins = $('.pin'), style = ele.style; style.position = "absolute"; style.top = minHeight + "px"; //设置当前元素的高度 style.left = pins[index].offsetLeft + "px"; arrHeight[index] += ele.offsetHeight; } //初始化时执行函数 var init = function() { var pins = $(".pin"), col = columns(); setCenter(); //设置包裹容器的宽度 for (var i = 0, pin; pin = pins[i]; i++) { if (i < col) { //存储第一排的高度 arrHeight.push(pin.offsetHeight); } else { overLoad(pin); //将元素的位置重排 } } }
合計 7 つの関数 (大きな関数) と 1 つの変数があります。 そのアイデアについて話しましょう。 まず、ページがロードされた後に実行される関数は init です。js プログラムにはその入り口が必要であることを知っておく必要があります。 次に、init 関数本体を深く掘り下げて観察します。 init で実行されるビジネス ロジックは、要素の最初の行の高さを保存し、残りの要素を再配置することです。 columns 関数を使用して、現在のウィンドウに配置できる列の最大数を取得し、コンテナーの中心を設定します (パディングによって設定するだけです)。 次に、ピンのセル ボックスをトラバースし、最初の列の高さを保存します。 arrHeight 配列の要素の行を追加し、残りの要素を追加します。 以下の要素が並べ替えられます。 他の機能については説明の必要はありません。 overLoad 関数に注目してみましょう。
2. オーバーロード
var overLoad = function(ele) { var index = getIndex(arrHeight), minHeight = Math.min.apply(null, arrHeight), //获取最小高度 pins = $('.pin'), style = ele.style; style.position = "absolute"; style.top = minHeight + "px"; //设置当前元素的高度 style.left = pins[index].offsetLeft + "px"; arrHeight[index] += ele.offsetHeight; }
overLoad には最小の高さのインデックスを取得する getIndex 関数があり、受信する ele 要素の位置 (絶対位置) を配列内の最小の高さの px 値に設定できます。 left は、Index 要素の左マージン位置に設定されます。 最後に高さを更新します。これで十分です。
3. 読み込み場所を設定します
var dataInt = [{ 'src': '1.jpg' }, { 'src': '2.jpg' }, { 'src': '3.jpg' }, { 'src': '4.jpg' }, { 'src': '1.jpg' }, { 'src': '2.jpg' }, { 'src': '3.jpg' }, { 'src': '4.jpg' }]; function isLoad() { //是否可以进行加载 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop, wholeHeight = document.documentElement.clientHeight || document.body.clientHeight, point = scrollTop + wholeHeight; //页面底部距离header的距离 var arr = $('.pin'); var lastHei = arr[arr.length - 1].getBoundingClientRect().top; return (lastHei < point) ? true : false; } //处理滑动 var dealScroll = (function() { var main = $('#main')[0], flag = true; return function() { if (isLoad() && flag) { for (var i = 0, data; data = dataInt[i++];) { var div = document.createElement('div'); div.innerHTML = temp(data.src); div.className = "pin"; main.appendChild(div); overLoad(div); //和上面的overload有耦合性质 } flag = false; setTimeout(function() { //控制滑行手速,时间越长对速度的滑动时间影响越大。 flag = true; }, 200); } } })(); function temp(src) { return ` <div class="box"> <img src="http://cued.xunlei.com/demos/publ/img/P_00${src}"/> </div> `; }
実際には、本質は前の部分にあります。これは、データをロードするための単なる手段です。もちろん、クリックしてロードすることも、他のロード方法を使用することもできます。 もちろん、どのように設定するかは完全にあなた次第です。 したがって、トレンドに従って、下にスクロールして読み込んでください。 続行して、関数 ->dealScroll というエントリを見つけます。この関数のタスクは、isload 関数を通じて読み込みを実行できるかどうかを判断することです。 isload 関数を見てみましょう。これがローリングロードの重要なポイントです。
function isLoad() { //是否可以进行加载 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop, wholeHeight = document.documentElement.clientHeight || document.body.clientHeight, point = scrollTop + wholeHeight; //页面底部距离header的距离 var arr = $('.pin'); var lastHei = arr[arr.length - 1].getBoundingClientRect().top; return (lastHei < point) ? true : false; }
ビューポートからのページ下部(ツールバー下部)の位置と最後の要素の絶対位置を計算により比較し、スライド距離を超えた場合に読み込み可能となります。
はい~終わりました。
dealScroll
に戻る
次のステップは、読み込み部分を見ていきます。この部分については、実際には何も言うことはありません。それは、div ノードを作成し、それをコンテナーの最後に配置し、overLoad 関数を使用してその位置を処理することです。ノード。 さらに、関数の最後に、スライド速度を制御するトリックを設定しました。関数を調整することで、リクエストが遅すぎてユーザーが繰り返しリクエストを送信し、リソースが無駄になるのを防ぐことができます。
その後、この部分は終了する可能性があります。
4. レスポンシブ
最後の部分は応答性です。カプセル化が適切に行われていれば、この部分も非常に単純です。実際には、この部分はサイズ変更イベントを追加するだけです。引き続きエントリ関数を探してみましょう。
var resize = (function() { var flag; return function(fn) { clearTimeout(flag); flag = setTimeout(function() { //函数的节流,防止用户过度移动 fn(); console.log("ok") }, 500); } })();
同様に、ここでは関数スロットリングの考え方が使用されています。プログラマーとして、ユーザーが何もすることができないなどと考えてはいけないことを知っておく必要があります。たとえば、何もすることがないときにブラウザ ウィンドウを再生、ズームイン、ズームアウト、そして拡大... 実際、私はよくこれをします。彼女もいないし、コードを書くのに飽きたので、ブラウザをドラッグして再生するだけです。 したがって、私たちの 1 頭の犬のニーズを考慮すると、機能スロットルを使用することが非常に必要です。 子供靴に興味がある場合は、以前の記事を参照して詳細を学ぶことができます。 説明すると、ここでのコールバック関数は init 関数を指しますが、init にいくつかの変更を加える必要があります。詳細を参照してください。
var update = function(ele) { //当resize的时候,重新设置 ele.style.position = "initial"; } //初始化时执行函数 var init = function() { var pins = $(".pin"), col = columns(); arrHeight = []; //清空高度 setCenter(); //设置包裹容器的宽度 for (var i = 0, pin; pin = pins[i]; i++) { if (i < col) { //存储第一排的高度 arrHeight.push(pin.offsetHeight); update(pin); } else { overLoad(pin); //将元素的位置重排 } } }
上面需要加入update,對新的第一排元素進行更新。
然後就可以直接搬過來使用即可。
這就是絕對是版面的大部分內容了,關於javascript瀑布流另一種版面方式請參考下一篇文章《詳解javascript實現瀑布流列式版面》。