⭐️ 核心思路
- 找到第一次排完,高度最小的那个列
- 把下一页第一张图放进去
- 再比较排完后高度最小的那一列
- 再把第二张图放进去
- 循环上边 3、4 步骤
;(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(){
// 当 页面已经滚动了的高度 + window自身高度 === 滚动+窗口高度 时
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;
data.forEach(function(elem, idx){
var oItem = doc.createElement('div'),
oImg = new Image(),
oTitle = doc.createElement('div'),
// 第一张图片没有左间距,用 (i + 1) % 列数 === 1 去判断,代表是每一行第一张图
// 每行的后续图片的 left 定位值,就是 (i * (每列宽度 + 间隔))
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');
// 设置第一页的第一行所有图片的top、left
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';
});
}
}
// 数组只会有 column 个,保存的是每一列的当前总和高度
// 该方法用来计算数组中最小高度的那一项的idx
function getMinIdx(arr) {
return [].indexOf.call(arr, Math.min.apply(null, arr));
}
window.Waterfall = Waterfall;
})(document);