WEB前端——JS实现瀑布流
一、简介
1、什么是瀑布流?
瀑布流式布局:一种较为流行的页面布局,视觉表现为参差不齐的多栏布局。随着滚动条向下滚动,不断加载数据块并附加至当前尾部。
特点:整版以图片为主,大小不一的图片按照一定的规律排列。
二、实现效果
1、图片分四列展示
2、向下滚动,自动加载数据并渲染显示。
三、具体实现
1、架构:用ul-li列表结构,每个li中插入div作为图片单元。
2、样式:重点是掌握浮动流
3、功能:
Ajax获取数据->success函数调用renderDom函数
->滚动滑轮重新获取数据
代码如下:
瀑布流代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
list-style:none;
padding:0;
margin:0;
}
.wrapper{
border:1px solid black;
width:960px;
margin:0 auto;
background-color: #eee;
}
.wrapper::after{
content:"";
display:block;
clear:both;
}
.item{
float:left;
width:25%;
}
.item div{
background-color:#fff;
margin:10px;
padding:10px;
}
.item img{
width:100%;
}
</style>
</head>
<body>
<ul class="wrapper">
<li class="item">
<!-- <div>
<img src="./image/1.jpg" alt="第一张照片">
<p></p>
</div> -->
</li>
<li class="item">
<!-- <div>
<img src="./image/2.jpg" alt="第二张照片">
<p></p>
</div> -->
</li>
<li class="item">
<!-- <div>
<img src="./image/3.jpg" alt="第三张">
<p></p>
</div> -->
</li>
<li class="item">
<!-- <div>
<img src="./image/4.jpg" alt="第四张">
<p></p>
</div> -->
</li>
</ul>
<script src="./ajax.js"></script>
<script>
//从第71行到第120行可以显示,但是没有按照想要的顺序排列。原因是由于图片加载需要时间,(异步读取数据)
//比如,第一张图片还没加载完,就在判断第五个图片需要加在何处(此时可以认为第一列为0)那么就造成了第五张图片在第一列加载;
//解决方案:预留图片的高度 判断 offsetHeight和pageYoffset+window.innerHeight的大小判断是否空白。
function getData(){
ajax({
url:"./data.json",
method:"GET",
success:function(data){
console.log(data);
renderDom(data);
lock=false;
}
});
}
getData();
//图片真实的宽度
var imgWidth=document.querySelector('.item').offsetWidth-40;
//渲染dom结构
function renderDom(data){
// for(var i=0;i<data.length;i++)
var oLi=document.getElementsByClassName('item');
data.forEach(function(item){//每一个item都需要加入dom
//查找最短列,并且向最短列里添加Dom结构
//最短列的索引值
var index=getMinLi().minIndex;
console.log(index);
//创建dom
var dom=createImg(item);
//将dom加入
oLi[index].appendChild(dom);
})
}
//查找最短列
function getMinLi(){
//获取到最短的li
var items=document.getElementsByClassName('item');
//minIndex代表最短列的索引值
var minIndex=0;
var minHeight=items[0].offsetHeight;
for(var i=0;i<items.length;i++){
if(minHeight>items[i].offsetHeight){
minIndex=i;
minHeight=items[i].offsetHeight;
}
}
return {
minIndex,
minHeight
}
}
function createImg(data){
// <!-- <div>
// <img src="./image/4.jpg" alt="第四张">
// <p></p>
// </div> -->
var oDiv=document.createElement('div');
var img=new Image();
img.src=data.img;
//在保留图片原来的宽高比的情况下预留img的高度
//图片的原始宽高为data.width / data.height=img.width/img.height
img.height=imgWidth*data.height/data.width;
var oP=document.createElement('p');
oP.innerText=data.desc;
oDiv.appendChild(img);
oDiv.appendChild(oP);
return oDiv;
}
//lock代表当前是否正在网络请求数据过程当中
// var lock=false;
//延迟触发网络请求
var timer=null;
//监听滚动事件
window.onscroll=function(){
//判断当前页面是否出现空白区域
//如果出现空白区域,则需要重新获取数据,渲染页面
clearTimeout(timer);
//判断最短列同滚动距离和可视区之和
if(getMinLi().minHeight<window.pageYOffset+window.innerHeight){
// //性能优化
// //1、当当前有网络请求的时候不予发送数据
// if(!lock){
// lock=true;//保证getData()互斥访问,同步与互斥
// getData();
// }
//2、在不断的滚动滚动条的时候,不进行网络请求,只有停止滚动才会进行请求
timer=setTimeout(function(){
getData();
},500);
}
</script>
</body>
</html>
自制json数据:
//json 文件
[
{
"img":"image/1.jpg",
"desc":"第1张图片",
"height":1138,
"width":640
},
{
"img":"image/2.jpg",
"desc":"第2张图片",
"height":1080,
"width":1920
},
{
"img":"image/3.jpg",
"desc":"第3张图片",
"height":640,
"width":400
},
{
"img":"image/4.jpg",
"desc":"第4张图片",
"height":1381,
"width":640
},
{
"img":"image/5.jpg",
"desc":"第5张图片",
"height":681,
"width":400
},
{
"img":"image/6.jpg",
"desc":"第6张图片",
"height":1067,
"width":1919
},
{
"img":"image/7.jpg",
"desc":"第7张图片",
"height":889,
"width":500
},
{
"img":"image/8.jpg",
"desc":"第8张图片",
"height":1139,
"width":640
},
{
"img":"image/9.jpg",
"desc":"第9张图片",
"height":795,
"width":460
},
{
"img":"image/10.jpg",
"desc":"第10张图片",
"height":1080,
"width":1920
},
{
"img":"image/11.jpg",
"desc":"第11张图片",
"height":1920,
"width":1080
},
{
"img":"image/12.jpg",
"desc":"第12张图片",
"height":1871,
"width":1080
},
{
"img":"image/13.jpg",
"desc":"第13张图片",
"height":429,
"width":650
},
{
"img":"image/14.jpg",
"desc":"第14张图片",
"height":1080,
"width":1920
},
{
"img":"image/15.jpg",
"desc":"第15张图片",
"height":450,
"width":500
},
{
"img":"image/16.jpg",
"desc":"第16张图片",
"height":1070,
"width":602
},
{
"img":"image/17.jpg",
"desc":"第17张图片",
"height":750,
"width":468
},
{
"img":"image/18.jpg",
"desc":"第18张图片",
"height":1280,
"width":800
},
{
"img":"image/19.jpg",
"desc":"第19张图片",
"height":1846,
"width":1080
},
{
"img":"image/20.jpg",
"desc":"第20张图片",
"height":1215,
"width":700
}
]
ajax封装:
/**
* @param {Object} options
* @desc 封装一个ajax函数,使所有网络请求都用该函数。
* 参数:
1.method:请求方式
2.url:请求地址
3.data:请求参数
4.isAsync:是否异步
5.success:成功拿到数据后做的功能
6.error:失败的回调函数。
当前函数有局限性:只能为字符串
method只能为get和post
**/
function ajax(options){
var method=options.method||"GET";
var url=options.url||"";
var data=options.data||"";
var isAsync=options.isAsync==undefined?true:toptions.isAsync;
var success=options.success||function(){};
var error=options.error||function(){};
var xhr=null;
if(window.XMLHttpRequest){
xhr=new XMLHttpRequest();
}else if(window.ActiveXObject){
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}else{
return alert("该浏览器不支持XMLHttpRequest");
}
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if(xhr.status==200){
//接收到数据之后的处理
success(JSON.parse(xhr.responseText));
}
}
}
xhr.onerror=function(e){
error("error");
}
//同一将用户传过来的参数方式转换为大写。
// method=method.toUpperCase();
if(method=="GET"){
if(url.indexOf('?')>-1){//判断url中是否有问号
//判断问号的位置是否在最后,如果是则直接拼接,否则证明有数据
if(url.indexOf('?')===url.length-1){
url+=data;
}else{
url+='&'+data;
}
}else{
url+='?'+data;
}
xhr.open(method,url,isAsync);
xhr.send();
}
}