講一下大概的原理吧,還是先上圖:
功能描述:
技術實現方案:
先梳理一下從加載到顯示的流程:
1. 加載數據
2. 拼接HTML寫入到頁面
3. 檢查剛剛寫入的HTML中的img是否全部加載完成,如果是,進入5、否則進入4
4. 等待圖片加載完成
5. 計算每個元素的位置
一開始的時候最頭疼的是如何定位的問題,後來經過朋友指導終於解決:計算總共有多少列圖片並且把每一列的高度都放到一個數組裡面。每當一張圖片加載完成的時候就查找這個數組裡面最小的值,並且定位當前圖片的top設置為這個值,完成後把這個圖片的高度加上數組裡面的最小值並且返回到數組裡面,依次類推。
PS:因為這個功能代碼太多,只能作基本的簡單分解代碼了:
// 創建用於記錄每列高度的數組 _getLowestCol: function() { t._cols = new Array(5),min = 0; // 初始化為0 for (var i = 0; i < t._cols.length; i++) { if (cols[i] < cols[min]) { min = i; } return min; } }, _reposition: function() { t._grids.each(function(i, grid) { //先顯示出來 grid = $(grid).show(); var height = grid.outerHeight(), min = t._getLowestCol(); // 定位 grid.animate({ left: (t._colWidth + t._colSpacing) * min, top: t._cols[min], opacity: 1 },1000); // 記錄高度 t._cols[min] += height; }); }
其次開發過程中遇到的難題是:因為如上圖所示,鼠標移動到菜單欄需要切換圖片列表,並且分別需要用瀑布流加載不同類型的數據。所以要處理在切換頁面的時候如何才能做到每個頁面只執行一次代碼請求接口,而不需要每一次切換都重新請求數據接口,僅僅執行切換顯示圖片列表的操作就可以了。
考慮到每一個菜單都有一個自定義屬性,所以這個問題輕易地解決了:建立一個對象來記錄當前菜單是否已經執行過代碼,如果沒有就執行請求數據 。
var isLoad = {};//是否載入過 labelType.mouseover(function() { var i = $(this).index(); var api = _this.attr('api');//接口標識 if(! isLoad[ api ]){ isLoad[ api ] = i; loadData(wrapper, api); } });
以下為全部代碼:
html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style type="text/css"> *{margin:0;padding:0;} ul,li{ list-style-type:none;} li img{width:100%;list-style:none;} </style> </head> <body> <div class="photo_box"> <ul id="container" style="border:1px solid #000;width:80%;height:600px;overflow:hidden;margin:0 auto;position: relative;"> </ul> <div id="loading" class="loading" style="text-align: center;margin-top: 20px;font-size: 1.2em;">加載中...</div> <div id="more" class="more"style="text-align: center;margin-top: 20px;font-size: 1.2em;"><input type="button" value="更 多" id="clear" /></div> </div> <script type="text/javascript" src="../../lib/seajs/sea.js"></script> <script type="text/javascript" src="../../lib/base/1.0.x/base.js"></script> <script type="text/javascript"> seajs.use(['lib/jquery/1.11.x/index.js', '_example/waterFall_1.1/waterfall.js'], function($, waterFall) { waterFall.init({ container: $('#container'), dataURL: 'http://www.woxiu.com/index.php?action=Index/Main&do=ApiZhuboGrade', dataType: 'jsonp', template: '<% for (var i = 0; i < data.length; i++) { %>' + '<li style="display: none;">' + '<img src=" <%-data[i].room_img%> ">' + '</li>' + '<% } %>', colWidth: 200, colSpacing: 10, rowSpacing: 15, page: 1, pageEnd: 8, }); // 限制同時展示的頁數 var loadCounter = 1; function pageNum(){ if (loadCounter >= 3) { $('#more').show(); $('#loading').hide(); return true; } else { loadCounter++; $('#more').hide(); $('#loading').show(); } return false; } $('#clear').click(function() { loadCounter = 1; waterFall._loadNext(); }); }); </script> </body>
js:
/** * 瀑布流布局組件類 * @param {Object} options 組件設置 * @param {NodeList} options.container 瀑布流容器 * @param {String} options.dataURL 數據地址 * @param {String} [options.dataType='jsonp'] 數據類型,json或jsonp * @param {String} options.template 模板編輯 * @param {Number} [options.colWidth] 圖片大小。 * @param {Number} [options.colSpacing] 列間隔。 * @param {Number} [options.rowSpacing] 行間隔。 * @param {Number} [options.page=1] 數據開始頁碼 * @param {Number} [options.pageEnd] 數據末尾頁碼 * @pageNum() 函數,如果不需要現在加載也是,需要把函數裡面的判斷去掉。 從加載到顯示的流程 1. 加載數據 2. 拼接HTML寫入到頁面 3. 檢查剛剛寫入的HTML中的img是否全部加載完成,如果是,進入5、否則進入4 4. 等待圖片加載完成 5. 計算每個元素的位置 */ define(function(require, exports, module) { 'use strict'; var Tmpl = require('lib/tmpl/2.1.x/index.js'), $ = require('lib/jquery/1.11.x/index.js'); var waterFall = { init: function(options) { var t = this; t._container = options.container; t._template = options.template; t._colWidth = options.colWidth; t._colSpacing = options.colSpacing; t._rowSpacing = options.rowSpacing; t.dataURL = options.dataURL; t.dataType = options.dataType; t.page = options.page; t.pageEnd = options.pageEnd; t._switch = false; //計算有幾列 總寬度 / (列寬 + 列間隔) t._totalCols = parseInt(t._container.width() / (t._colWidth + t._colSpacing)); // 創建用於記錄每列高度的數組 t._cols = new Array(t._totalCols); // 初始化為0 for (var i = 0; i < t._cols.length; i++) { t._cols[i] = 0; } t._loadingPage = options.page || 0; t._loadNext(options); //下拉滾動條加載 var lastTime = new Date().getTime(); $(window).scroll(function() { if ( !t._switch ) { //判斷是否滾動過快,在ie下 var thisTime = new Date().getTime(); if (thisTime - lastTime < 50) { console.log(thisTime - lastTime); lastTime = thisTime; return; } if ($(window).scrollTop() + $(window).height() >= document.documentElement.scrollHeight) { lastTime = thisTime; t._loadNext(); } } }); }, //加載器 _loadNext: function(t) { var t = this; t._switch = true; //請求數據 if (!t.trigger) { $.ajax({ url: t.dataURL, data: { page: ++t._loadingPage }, dataType:t.dataType, success: function(response){ t.trigger = t._completeLoading(response); }, error:function(){console.log('Error! 請求有誤');} }); } return false; }, //加載完數據調用此函數 _completeLoading: function(result) { var t = this; if (t._loadingPage >= t.pageEnd) { $('#more').hide(); $('#loading').html('<p>已是最後一頁了喔 ^_^ ^_^</p>'); return true; } else { //if (!pageNum()) { t._add(result); //}; } return false; }, //添加格子 _add: function(result) { var t = this, grids = ''; //調用模板 var content = Tmpl.render(t._template, {data:result.data}); //原始定位 t._grids = $(content).css({ position: 'absolute', left: t._container.width(), top: t._container.height(), width: t._colWidth, opacity: 0 }); //把Html添加到容器 t._container.append(t._grids); // 執行一次_reposition,如果所有圖片都加載完成,該方法返回true,否則返回false if ( !t._reposition() ) { // 有圖片未加載完,監聽onload和onerror t._grids.find('img').bind('load error', function() { this.loaded = true; // 有圖片加載完成,再次執行_reposition if (t._grids) { t._reposition(); } }); } }, // 此方法用於獲取高度最低的列 _getLowestCol: function() { var cols = this._cols, min = 0; for (var i = 1; i < cols.length; i++) { if (cols[i] < cols[min]) { min = i; } } return min; }, //定位 _reposition: function() { var t = this, allImgsLoaded = true; // 檢測圖片是否全部加載完成 t._grids.find('img').each(function(i, img) { if (!img.loaded && !img.complete) { allImgsLoaded = false; } return allImgsLoaded; }); if (allImgsLoaded) { t._grids.each(function(i, grid) { //先顯示出來 grid = $(grid).show(); var height = grid.outerHeight(), min = t._getLowestCol(); // 非第一行的時候,要加上行間隔 if (t._cols[min]) { t._cols[min] += t._rowSpacing; } // 定位 grid.animate({ left: (t._colWidth + t._colSpacing) * min, top: t._cols[min], opacity: 1 },1000); // 記錄高度 t._cols[min] += height; }); // 重設外層容器高度為最高列高度 t._container.css( 'height', Math.max.apply(Math, t._cols) ); t._switch = false; delete t._grids; } return allImgsLoaded; }, } return waterFall; });
以上就是本文的全部內容,希望對大家學習javascript程序設計有所幫助。