假如我们是要将所有的图片内容分成3列,实现定宽的按需加载
瀑布流实现思路:
1、布局完成之后,用ajax请求相应的图片数据,
2、考虑到图片的长度不一,在渲染的时候,先判断一个每个列中那列是最短的,
3、找到最短的列之后,将图片渲染进来即可
瀑布流实现可能遇到的问题:
1、在判断最短列的时候,可能会用到for循环,由于图片请求是异步,循环不会等异步结束之后再走,所以会出现判断出最短列的时候,将图片渲染上,在还没有拿到图片的时候,没有高度,下一次循环依然将这列判断为最短的,下一张图片依然在这列渲染,之后前面的图片获取完成之后,就会出现问题
解决方案:
1、 使用递归,和图片的预加载结合实现
2、后端给我们提供图片的宽高值,我们直接给图片设置好宽高,这样在数据请求到之前就可以将高度撑开
如果是我们定宽,比如是200px,但是后端传给我们的宽度可能是其他的数值,这之后我们就直接用我们设置好的固定值200px就好
高度 = 后端提供的高度 * (200/后端给的宽度,这样就可以解决图片由于定宽而产生拉伸的问题
瀑布流案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ajax按需加载</title>
<link rel="shortcut icon" href="#" />
<style>
body,p,h2{
margin: 0;
}
img{
vertical-align: top;
}
.list{
margin: 0;
padding: 0;
list-style: none;
font: 18px/30px "宋体";
}
.list li{
width: 400px;
float: left;
margin: 10px;
}
.list .pic{
margin-bottom: 40px;
}
.list .pic img{
width: 400px;
}
.list .title{
font-weight: normal;
background: #eee;
}
</style>
</head>
<body>
<ul class="list">
<li></li>
<li></li>
<li></li>
</ul>
<script>
var list = document.querySelector('.list');
let item = document.querySelectorAll('.list li');
let page = 1; //获取的页码,默认获取第一页的内容
let off = true; //设置请求开关,以免发起过多的请求
getlist(); //初始化
window.onscroll =function(){
var shortId = shortList()
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
lastOne = item[shortId]
if(getTop(lastOne) < document.documentElement.clientHeight + scrollTop){
if(off){
off = false;
page++;
getlist();
}
}
}
function getlist(){
ajax({
url:'getPics.php',
data:{cpage:page},
fn:function(data){
var data = JSON.parse(data);
console.log(data)
if(!data.length){
return;
}
//创建html结构,之前是想着直接用模板字符串来创建结构,然后出现了一些问题,发现还是这样更加好处
for(var i=0; i<data.length; i++){
var picHeight = (data[i]).height;
var picWidth = (data[i]).width;
var shortId = shortList()
var pic = document.createElement('div');
pic.classList.add('pic')
var img = document.createElement('img')
img.src = data[i].image;
img.style.height = picHeight * (300/picWidth) +'px'
img.classList.add('img')
pic.appendChild(img);
var title = document.createElement('p')
title.classList.add('title')
title.innerText = data[i].title
pic.appendChild(title)
item[shortId].appendChild(pic)
}
off = true;
}})
}
function shortList(){ //获得最短列
let aLi = document.querySelectorAll('.list li');
let index = 0;
let height = aLi[index].offsetHeight;
for(let i=0; i<aLi.length; i++){
if(aLi[i].offsetHeight < height){
index = i
height = aLi[i].offsetHeight
}
}
return index;
}
function getTop(obj){
let top = 0;
if(obj){
top += obj.offsetTop;
obj = obj.offsetParent;
}
return top;
}
//-------------------------- ajax函数封装 ---------------------
function ajax(init){
let option = { //设置一些参数默认值
method: 'GET',
data:{},
async:true
}
let xhr = null;
//声明一个Http请求,并且做IE的兼容,如果是用的if判断的话,可以判断window.XMLHttpRequest是否存在
try{
xhr = new XMLHttpRequest();
}catch(e){
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
for(let a in init){
option[a] = init[a];
}
//将请求数据方式字母都转化为大写字母
option.method = option.method.toUpperCase();
//对get方式进行处理
if(option.method == 'GET'){
option.url+= '?'+ dealData(option.data);
xhr.open('GET',option.url,true)
xhr.send();
}
else if (option.method == 'Post'){
xhr.open('Post',option.url,true);
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')
xrh.send(dealData(option.data));
}
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
if(xhr.status==200){
option.fn && option.fn(xhr.responseText);
}else{
alert('出错了,Err:'+ xhr.status);
}
}
}
function dealData(data){
let arr = []
for(let i in data){
arr.push(encodeURI(i) + "="+encodeURI(data[i]));
}
return arr.join('&');
}
}
</script>
</body>
</html>