一、瀑布流的实现
(1)书写思路
- 保存图片高度到数组:先把第一行图片的高度求出并放在一个数组
- 找到最小值及索引号:根据Math.min找到数组中的最小数,再根据indexOf找到出相对应的索引号
- 设置第六张图左边距:根据索引找到数组中的图片,把它的offsetLeft值赋给第六张图片
- 设置第六张图上边距:再根据索引找到数组中保存的高度+10,赋给第六张图片的offsetTop
- 改变当前索引的高度:把当前索引高度更改为数组最低高度+第六张图片的高度+10
第一行图片确定好了以后下面的图片就不用像第一行这么排了,因为下面的图片是一张一张的排的,它的left值和top值和第一行的不一样了,它的left值是数组最短的那一列,top值是数组最短高度加上10
每次图片处理完了以后,都要改变的当前idx值的高度
(2)源码
; (function (doc) {
var oItems = doc.getElementsByClassName('wf-item'),
oItemsLen = oItems.length,
_arr = [];
var init = function () {
setImgPos()
}
function setImgPos() {
var item;
for (var i = 0; i < oItemsLen; i++) {
item = oItems[i];
item.style.width = '232px';
// 给第一行图片的top值设置为零,并把高度放入数组
if (i < 5) {
_arr.push(item.offsetHeight);
item.style.top = '0';
if ((i + 1) % 5 === 1) { // 找出每行的第一张图片,并把left值设置为0
item.style.left = '0';
} else {
item.style.left = i * (232 + 10) + 'px';
}
} else {
minIdx = getMinIdx(_arr);
item.style.left = oItems[minIdx].offsetLeft + 'px';
item.style.top = (_arr[minIdx] + 10) + 'px';
_arr[minIdx] += (item.offsetHeight + 10);
}
}
}
function getMinIdx(arr) {
// 找数组里面最小数的索引号
return [].indexOf.call(arr, Math.min.apply(this, arr));
}
// 避免图片加载时的空白
window.onload = function () {
init();
}
})(document);
二、插件封装
(1)写前分析
配置项
- 外层盒子 oWrapper
- 列数 column
- 间隙 gap
(2)源码
普通版
; (function (doc) {
var Waterfall = function (wrapper, opt) {
this.oWrapper = doc.getElementsByClassName(wrapper)[0];
this.column = opt.column;
this.gap = opt.gap;
this.imgAPI = opt.imgAPI;
this.itemWidth = (this.oWrapper.offsetWidth - (this.column - 1) * this.gap) / this.column;
this.pageNum = 0;
this.pageSize = 0;
this.heightArr = [];
}
Waterfall.prototype = {
init: function () {
this.getImgDatas(this.pageNum);
this.bindEvent();
},
bindEvent: function () {
window.addEventListener('scroll', this.scrollToBottom.bind(this), false);
},
scrollToBottom: function () {
if (getScrollTop() + getWindowHeight() == getScrollHeight()) {
this.pageNum++;
if (this.pageNum <= this.pageSize - 1) {
this.getImgDatas(this.pageNum);
}
}
},
getImgDatas: function (pageNum) {
var _self = this;
xhr.ajax({
url: this.imgAPI,
type: 'POST',
dataType: 'JSON',
data: {
pageNum: pageNum,
},
success: function (data) {
if (data != 'NO DATA') {
var pageData = JSON.parse(data.pageData);
_self.pageSize = parseInt(data.pageSize);
_self.renderList(pageData, _self.pageNum);
}
}
})
},
renderList: function (data, pageNum) {
var _self = this,
oItems = null,
minIdx = -1; //数组索引保存默认值一定是-1
data.forEach(function (elem, idx) {
var oItem = doc.createElement('div'),
oImg = new Image(),
oTitle = doc.createElement('div'),
itemLeft = (idx + 1) % _self.column === 1 ? '0' : idx * (_self.itemWidth + _self.gap);
oItem.className = 'wf-item';
oItem.style.width = _self.itemWidth + 'px';
oItem.style.height = (elem.height * _self.itemWidth / elem.width + 44) + 'px';
oImg.src = elem.img;
oTitle.innerHTML = '<p>测试文本</p>';
oTitle.className = 'title-box';
oItem.appendChild(oImg);
oItem.appendChild(oTitle);
_self.oWrapper.appendChild(oItem);
oItems = doc.getElementsByClassName('wf-item');
if (idx < _self.column && pageNum == 0) {
_self.heightArr.push(oItem.offsetHeight);
oItem.style.top = '0';
oItem.style.left = itemLeft + 'px';
} else {
minIdx = getMinIdx(_self.heightArr);
oItem.style.left = oItems[minIdx].offsetLeft + 'px';
oItem.style.top = (_self.heightArr[minIdx] + _self.gap) + 'px';
_self.heightArr[minIdx] += (oItems[idx].offsetHeight + _self.gap);
}
oImg.style.opacity = '1';
});
}
}
function getMinIdx(arr) {
return [].indexOf.call(arr, Math.min.apply(null, arr));
}
// 抛到全局
window.Waterfall = Waterfall;
})(document);
优化版
; (function (doc) {
var Waterfall = function (wrapper, opt) {
this.oWrapper = doc.getElementsByClassName(wrapper)[0];
this.column = opt.column;
this.gap = opt.gap;
this.imgAPI = opt.imgAPI;
this.itemWidth = (this.oWrapper.offsetWidth - (this.column - 1) * this.gap) / this.column;
this.pageNum = 0;
this.pageSize = 0;
this.heightArr = [];
}
Waterfall.prototype.init = function () {
this.getImgDatas(this.pageNum);
this.bindEvent();
}
Waterfall.prototype.bindEvent = function () {
window.addEventListener('scroll', this.scrollToBottom.bind(this), false);
}
Waterfall.prototype.scrollToBottom = function () {
if (getScrollTop() + getWindowHeight() == getScrollHeight()) {
this.pageNum++;
if (this.pageNum <= this.pageSize - 1) {
this.getImgDatas(this.pageNum);
}
}
}
Waterfall.prototype.getImgDatas = function (pageNum) {
var _self = this;
xhr.ajax({
url: this.imgAPI,
type: 'POST',
dataType: 'JSON',
data: {
pageNum: pageNum,
},
success: function (data) {
if (data != 'NO DATA') {
var pageData = JSON.parse(data.pageData);
_self.pageSize = parseInt(data.pageSize);
_self.renderList(pageData, _self.pageNum);
}
}
})
}
Waterfall.prototype.renderList = function (data, pageNum) {
var oFrag = doc.createDocumentFragment();
data.forEach(function (elem, idx) {
var minIdx = getMinIdx(this.heightArr);
var oItem = doc.createElement('div'),
oImg = new Image();
var itemLeft = (idx + 1) % this.column === 1 ? '0' : idx * (this.itemWidth + this.gap),
minHeightElemLeft = minIdx === 0 ? 0 : (minIdx * (this.itemWidth + this.gap)),
itemHeight = elem.height * this.itemWidth / elem.width;
oItem.className = 'wf-item';
oItem.style.width = this.itemWidth + 'px';
oItem.style.height = (elem.height * this.itemWidth / elem.width) + 'px';
oImg.src = elem.img;
oItem.appendChild(oImg);
oFrag.appendChild(oItem);
if (idx < this.column && pageNum == 0) {
this.heightArr.push(itemHeight);
oItem.style.top = '0';
oItem.style.left = itemLeft + 'px';
} else {
oItem.style.left = minHeightElemLeft + 'px';
oItem.style.top = (this.heightArr[minIdx] + this.gap) + 'px';
this.heightArr[minIdx] += (itemHeight + this.gap);
}
oImg.style.opacity = '1';
}, this);
this.oWrapper.appendChild(oFrag);
}
function getMinIdx(arr) {
return [].indexOf.call(arr, Math.min.apply(null, arr));
}
// 抛到全局
window.Waterfall = Waterfall;
})(document);