图片瀑布流
#瀑布流  #Javascript  #jQuery 


图片瀑布流插件

图片瀑布流原理

其实整个图片瀑布流的实现原理比较简单,只要了解了整个流程即可。

根据上图,能够看出一个基本的瀑布流原理: 先放好第一排的图片,然后计算第一排图片的innerHeight,也就是高度值,找出高度值最小的,把下一张图片(这里是图片4)放到高度最小值的下面,后面的图片循环依此类推。

  • 一般来讲,瀑布流都是定宽
  • 列数可固定,可自适应(本例中为最开始固定列数)
  • 图片大小等比例缩放
  • 下拉ajax异步请求数据

基本上都是基于用absolute来定位图片的位置摆放。

一种新的解决思路

首先,根据插件可以预知具体的列数,那么就生成对应的几个容器DIV(float: left;),这样的好处:

  • 无需计算高度(但ajax获取的数据图片信息里面要包含图片的高宽)
  • 由于直接是DIV放DIV容器,布局默认的就可以,不用像上面一样计算复杂的absolute布局的div
  • 提高加载性能

使用方法:

// waterfall
$('#textBox').waterfall({
	col: 3, 
	width: 240,
	jsonURL: 'data/data.json',
	onAfterLoad: function (dom) {
		// TODO
	}
});

附插件代码(基于jQuery):

/**
 * Waterfall
 * @auth: Karl Luo([email protected])
 * @dependence jQuery
 * @createDate 04-19-2015
 * @usage:
 * <div id="testBox">
 *
 * </div>
 *
 * $('#testBox').waterfall({
 *      col: 3, 						// set the display column number
 *      width: 240,  					// set the each column color
 *      jsonURL: 'data/data.json',   	// provide a json URL for ajax
 *      //limit: 0,  					// the reserved parameter
 *      onAfterLoad: function(param){}	// add the callback for the every img rendering dom
 * });
 **/
(function($){
	$.fn.waterfall = function (options) {
		var flag = true,
			o = $(this),
			settings = {
				col: 3,
				width: 240,
				jsonURL: 'data/data.json',
				limit: 0, // -1 | 0 | 2000
				onAfterLoad: function (param) {}
			}, req = {
				/**
				 * request the json data from server
				 * @param {Object} options
				 * @param {Function} callback
				 */
				reqJsonData: function (options, callback) {
					$.ajax($.extend({
						type: 'POST',
						dataType: 'JSON'
					}, options, true)).done(function(data){
						if (data && $.isFunction(callback)) {
							callback(data.sort(_.jsObjQueue('timestamp')));
						}
					});
				}
			}, _ = {
				/**
				 * render the 3 column divs
				 */
				renderBox: function () {
					var divs = [], i = 0, size = settings.col;
					for (; i < size; i++) {
						divs.push('<div class="wf-box"></div>');
					}
					o.append(divs.join('')).append('<div id="loading">正在加载……</div>');
				},
				/**
				 * render the popup layer
				 * @param {String} data
				 */
				popupLayer: function (data) {
					var dom = '<div id="popup_div" class="popup-div"><div class="popup-div-content"><img src="' + data + '" alt=""/></div></div><div id="bg"></div>';
					$('body').append(dom);
					_.bindCloseEvent();
				},
				/**
				 * bind Close Event for popup layer
				 */
				bindCloseEvent: function () {
					$(document).click(function (e) {
						var pop = $('#popup_div');
						if (!pop.is(e.target) && pop.has(e.target).length === 0) {
							$('#bg, #popup_div').remove();
						}
					});
				},
				/**
				 * set the default position about the new img div
				 * @param {Object} data
				 */
				setDefaultPos: function (data) {
					var i = 0, size = data.length, colNo = settings.col, wfBoxes = $('.wf-box', o);
					for (; i < size; i++) {
						var item = data[i], dom = '<div class="mb20"><div class="wf-box-title"><a href="javascript:;"><img data-url="' + item['img']['img'] + '" src="' + item['img']['img'] + '" alt=""/></a><p><span>' + item['title'] + '</span></p></div><div class="wf-box-info"><span class="wf-box-info-price"><span>¥' + item['price'].toFixed(2) + '</span>元</span><span class="wf-box-info-sale">已售出<span>' + item['sale'] + '</span>次</span></div></div>';
						if (i < colNo) {
							$(wfBoxes[i]).append($(dom).fadeIn());
							$.isFunction(settings.onAfterLoad) && settings.onAfterLoad($(dom));
						} else {
							var minH = $(wfBoxes[0]).outerHeight(), j = 0, bSize = wfBoxes.length;
							for (; j < bSize; j++) {
								var wfH = $(wfBoxes[j]).outerHeight();
								if (wfH < minH) {
									minH = wfH;
								}
							}
							var key = _.getKey(wfBoxes, minH);
							$(wfBoxes[key]).append($(dom).fadeIn());
							$.isFunction(settings.onAfterLoad) && settings.onAfterLoad($(dom));
						}
					}
					$('img', o).css({'width': settings.width - 20}).click(function (e) {
						e.stopPropagation();
						var thiz = $(this);
						_.popupLayer(thiz.attr('data-url'));
					});
					$('p', o).css({'width': settings.width - 20});
				},
				/**
				 * determine the relevant key
				 * @param {Array} a
				 * @param {String} v
				 * @returns {*}
				 */
				getKey: function (a, v) {
					var i = 0, size = a.length, key;
					for (; i < size; i++) {
						if ($(a[i]).outerHeight() === v) {
							key = i;
						}
					}
					return key;
				},
				/**
				 * scroll down the scrollBar, and get More images
				 */
				loadMore: function () {
					$("#loading").fadeIn('fast');
					req.reqJsonData({url: settings.jsonURL}, function (data) {
						_.setDefaultPos(data);
						$('#loading').fadeOut('fast');
						flag = true;
					});
				},
				/**
				 * bind the scroll event with window Object
				 */
				scrollEvent: function () {
					$(window).scroll(function(){
						if (flag && ($(document).height() - $(this).scrollTop() - $(this).height() < 100)) {
							flag = false;
							_.loadMore();
						}
					});

				},
				/**
				 * get the queue about the sort result
				 * @param key
				 * @returns {Function}
				 */
				jsObjQueue: function (key) {
					return function (o, p) {
						var x, y;
						if (o && p && typeof o === 'object' && typeof p === 'object') {
							x = o[key];
							y = p[key];
							if (x === y) {
								return 0;
							}
							if (typeof x === typeof y) {
								return x < y ? 1 : -1;
							}
							return typeof x < typeof y ? 1 : -1;
						} else {
							return 1;
						}
					}
				}
		};

		settings = $.extend(settings, options);
		req.reqJsonData({url: settings.jsonURL}, function (data) {
			_.renderBox();
			_.setDefaultPos(data);
			_.scrollEvent();
		});
	};
})(jQuery);

附插件CSS代码:

#bg {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
}
#popup_div {
    position: fixed;
    z-index: 9999;
    opacity: 1;
    width: 70%;
    height: 75%;
    left: 15%;
    top: 10%;
    background-color: #fff;
    color: #000;
    border: 5px solid #ccc;
}
#popup_div .popup-div-content {
    text-align: center;
}
Published under (CC) BY-NC-SA