web学习-瀑布流布局(1)

时间:2022-10-23 15:37:02

在mooc网上学习了瀑布流布局的实现,自己就记录了一下,留作一个笔记^.^

瀑布流样式

在页面中有大大小小的box,box的宽度相同,高度不同,竖直排列成N列,当滚动条向下面滚动的时候自动加载box,形成瀑布流

基本结构

(1)html结构:

<body>
<div id="warp">
<div class='box'><div class='pic'><img></div><div>
</div>
</body>

(2)css样式:

* {
margin: 0;
padding: 0;
}

warp{
margin: 0 auto;
}

.box {
padding: 15px 0 0 15px;
float: left;
position: absolute;
}

.pic {
padding: 10px;
border: 1px solid #ccc;
border-right: 5px;
box-shadow: 0 0 5px #ccc;
}

.pic img {
width: 165px;
height: auto;
}

瀑布流实现原理

采用js来实现

  1. 在Css中已经把box都设置成绝对定位,通过box的top,left值来计算出一个盒子该出现的位置.
  2. 在js中维护一个数组,这个数组的长度是瀑布流的列数,数组的值储存键值对应的列的高度,arr[1]指的是第一列的总高度,以此类推.
  3. 新的box应该插入在当前页面所有列中最’短’的列,在arr中值最小既是最小的列,得到该最小值对应的索引就是最’短’ 的列.

滚动加载实现的方式:

  1. 在所有的box中找到排列最后的那个box(靠下面的box都行)
  2. 计算1中box的offsetTop(距离文档顶部的距离)+offsetHeight(box的高度)/2
  3. 计算屏幕的高度,doucment.documentElement.clientHeight
  4. 计算文档距离window的高度,也就是滚动条的高度:document.documentElement.scrollTop
  5. 如果2值<=(4值+3值)的话,那么就可以判断屏幕已经显示到底部了,要加载新的box了

数据请求的时刻:

  1. 页面加载完毕的时候,ajax.send(‘action=first’)
  2. 滚动条滚动到底部的时候ajax.send(‘action=next’)

代码片段

(1)ajax请求的代码

    /**
* [ajax description] ajax的处理
* @param {[string]} url [description] ajax post的地址
* @param {string} content [description] ajax send
* @return {[string]} json [description] json
*/

function ajax(url,content,callback){
var ajax = new XMLHttpRequest();
ajax.open('post',url);
ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
ajax.send(content);
ajax.onreadystatechange = function(){
if(ajax.readyState===4 && ajax.status ===200){
callback(ajax.responseText);
console.log(ajax.responseText);
}else{
return 'error';
}
}
}

(2)添加盒子的代码

    /**
* [Boxs description] 在页面中插入盒子
* @param {[document.node]} parent [description] 放入盒子的父节点
* @param {[array]} pics [description] 储存图片地址的数组
* @param {[int]} total [description] 盒子的数目
* @param {Function} callback(img,pic,box) [description] 回调函数(图片,图片父节点div,box.div)
*/

function Boxs(pics,total){
this.total = total || 1;
this.pictures = pics || null;
this.addBoxs = function(parent,callback){
for(var i = 0;i<total;i++){
var box = document.createElement('div');
box.className = 'box';
var pic = document.createElement('div');
pic.className = 'pic';
var img = document.createElement('img');
img.src = pics[i];
pic.appendChild(img);
box.appendChild(pic);
parent.appendChild(box);
img.onload = callback(img,pic,box);
}
}
}

(3)一些初始化(后台地址,维护的数组,初始化列的宽度)

    const url = './ajaxTest.php';
var boxWidthArr = [];
var boxWidth = 0 ;

(4)在window.onload中进行ajax请求,并且计算box的位置

window.onload = function(){
ajax(url,'action=first',function(response){
var json = JSON.parse(response);
boxWidth = json.width;
var boxRowNum = Math.floor((document.getElementsByTagName('body')[0].offsetWidth) / boxWidth);
for(var i=0;i<boxRowNum;i++){boxWidthArr[i] = 0;};
var box = new Boxs(json.files,json.files.length);
box.addBoxs(document.getElementById('warp'),function(img,pic,box){
// box添加以及计算
var minH = Math.min.apply(null,boxWidthArr);//计算储存列高度最小的那个高度
var minIndex = 0;
while(minIndex < boxWidthArr.length){if(boxWidthArr[minIndex] == minH) break;minIndex++;}//找到最小值的那个键值
box.style.top = minH + 15 + 'px';// top的计算是用最小值加上15px
box.style.left = minIndex*boxWidth + 'px';//left的值是最小值的那个索引乘上盒子的宽度
boxWidthArr[minIndex] += box.offsetHeight;//每次添加完box要更新所在列的高度对应数组中的值
});
})

(5)检查是否要加载图片了,就是滚动条是否滚动到底部了

function checkScrollSlider(){
var lasbox = document.querySelectorAll('.box')[document.querySelectorAll('.box').length-1];
var lastBoxDis = lasbox.offsetTop + Math.floor(lasbox.offsetHeight / 2);
var documentH = document.documentElement.clientHeight;
var scrollTop = document.documentElement.scrollTop;
return ((lastBoxDis <= scrollTop + documentH)?true:false);
};

(6)在window.onscroll中检查是否要加载图片了,没当滚动条动的时候就检查一次

    if(checkScrollSlider()){
ajax(url,'action=next',function(response){
var json = JSON.parse(response);
var box = new Boxs(json.files,json.files.length);
box.addBoxs(document.getElementById('warp'),function(img,pic,box){
// box添加以及计算
var minH = Math.min.apply(null,boxWidthArr);
var minIndex = 0;
while(minIndex < boxWidthArr.length){if(boxWidthArr[minIndex] == minH) break;minIndex++;}
box.style.top = minH + 15 + 'px';
box.style.left = minIndex*boxWidth + 'px';
boxWidthArr[minIndex] += box.offsetHeight;
});
})
}
}

最终的效果:

web学习-瀑布流布局(1)

学习总结:

(1)碰到的第一个问题就是img加载的问题.我当时是想是加一张图片就计算它的位置,还是等所有图片都加载完成了在整理他们的位置.后来决定加一张图片就计算位置.当时不知道img有个onload事件,每次都是在设置img的src之后就计算位置,每次计算的都是错误的(当时img根本没有加载完)….坑了,折腾啦好长时间
(2)第二个问题就是那个ajax.send(),它能发送一个http的请求头.但是一开始不知道,不知道怎么让后台代码区分是一开始加载的,还是后面滚动条触发加载的
(3)不能把代码写的很紧密.就采用回调的方式,也不知道这个方式是好是坏