瀑布流
案例:瀑布流图片加载。
分析:将图片放入规定的列中,先进行图片预加载,每次放入图片时判断哪列的高度最小,然后将图片放到高度最小的列中。
如果是自适应页面,需要监听浏览器尺寸改变事件(resize),修改已经加载的列和图片的宽度,当浏览器出现滚动条。body的宽度改变,也需要修改已经加载的列和图片的宽度。
注:将代码复制到编辑器里,格式化文档看起来会方便一些,可以自己存一些图片,图片的命名和路径修改下(修改n和src即可)
<!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>
body {
margin: 0;
padding: 0;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
ul::after {
content: "";
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
display: block;
}
li {
float: left;
}
</style>
</head>
<body>
<ul></ul>
<script>
//定义有多少列COL,列宽度COL
const COL = 5,
GAP = 10;
//将每一列放入liList数组,
//将每列的高度放入heightList数组,每次判断最小高度放入图片,
//n表示起始图片名的(2-79)
var liList = [], heightList = [], n = 2;
//定义每列的宽度,定义bodyWidth来记录初始可视窗口的宽度
var width, bodyWidth;
init();
function init() {
//获取可视窗口的宽度
bodyWidth = document.body.clientWidth;
//求出每列的宽度
width = (bodyWidth - GAP * (COL - 1)) / COL;
var frag = document.createDocumentFragment();
//根据COL创建列
for (var i = 0; i < COL; i++) {
var li = document.createElement("li");
//设置li的样式
Object.assign(li.style, {
width: width + "px",
marginLeft: i === 0 ? "0px" : GAP + "px"
});
//每创建一列,将创建好的li放入liList数组中
liList.push(li);
//每创建一列,将heightList中数组对应的高度初始化为0
heightList.push(0);
//每创建一列,将创建好的列放入碎片容器frag中
frag.appendChild(li);
}
//将碎片容器frag放入到页面ul中
document.querySelector("ul").appendChild(frag);
//执行预加载图片函数
loadImg();
//添加浏览器尺寸改变事件,当浏览器宽度改变,重新计算width
window.addEventListener("resize",resize);
//懒加载:添加滚动条滚动事件,当滚动条滚动时,继续加载后三屏的内容
window.addEventListener("scroll",scrollHandler);
}
//预加载图片函数
function loadImg() {
//创建图片
var img = new Image();
//添加图片路径
img.src = `./imgs/${n}-.jpg`;
//给图片添加加载完成事件
img.addEventListener("load", loadHandler);
}
function loadHandler(e) {
//复制img,将每次复制的img放入li中
//如果直接放入,每次img的url改变,最终只放入最后一张图片
var img = this.cloneNode(false);
//给图片添加宽度
img.style.width = width + "px";
//求出heightList中最小的一项
var min = Math.min.apply(null, heightList);
//得到最小一项额索引值,这个索引值对应liList中的列
var index = heightList.indexOf(min);
//将图片放入高度最小的那一列
liList[index].appendChild(img);
//将放入图片的高度累加到最小项上,
//注意先放图片,再计算高度
heightList[index] += img.height;
/* 当浏览器出现滚动条时,bodyWidth的值发生改变,
应该重新计算width,并将每列的宽度和之前放入的图片的宽度也改变 */
if (bodyWidth !== document.body.clientWidth) resize();
//图片一共79张,n大于79张跳出,不再加载图片
n++;
if (n > 79) return;
this.src = `./imgs/${n}-.jpg`;
}
//当浏览器窗口宽度发生改变,重新设置li和img的宽度
function resize() {
//重新获取当前可视窗口的宽度
bodyWidth = document.body.clientWidth;
//重新求出每列的宽度
width = (bodyWidth - GAP * (COL - 1)) / COL;
//设置每列的宽度和之前放入的图片的宽度
var lis = Array.from(document.querySelector("ul").children);
lis.forEach((item, index) => {
//设置每列的宽度
item.style.width = width + "px";
var height = 0;
//设置之前放入图片的宽度
for (var i = 0; i < item.children.length; i++) {
item.children[i].style.width = width + "px";
//重新计算每列的高度
height += item.children[i].height;
}
//更新heightList中每列的高度
heightList[index] = height;
})
}
</script>
</body>
</html>
懒加载
分析:每次只加载可视窗口高度*3高的内容。
监听滚动条滚动事件,当滚动条滚动超过可视高度时,继续加载图片。
<!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>
body {
margin: 0;
padding: 0;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
ul::after {
content: "";
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
display: block;
}
li {
float: left;
}
</style>
</head>
<body>
<ul></ul>
<script>
const COL = 5,
GAP = 10;
var liList = [], heightList = [], n = 2;
var width, bodyWidth,imgs;
init();
function init() {
bodyWidth = document.body.clientWidth;
width = (bodyWidth - GAP * (COL - 1)) / COL;
var frag = document.createDocumentFragment();
for (var i = 0; i < COL; i++) {
var li = document.createElement("li");
Object.assign(li.style, {
width: width + "px",
marginLeft: i === 0 ? "0px" : GAP + "px"
});
liList.push(li);
heightList.push(0);
frag.appendChild(li);
}
document.querySelector("ul").appendChild(frag);
loadImg();
window.addEventListener("resize",resize);
//添加滚动条滚动事件,滚动条滚动时,继续加载后面三屏的内容
window.addEventListener("scroll",scrollHandler);
}
function loadImg() {
imgs = new Image();
imgs.src = `./imgs/${n}-.jpg`;
imgs.addEventListener("load", loadHandler);
}
function loadHandler(e) {
var img = this.cloneNode(false);
img.style.width = width + "px";
var min = Math.min.apply(null, heightList);
var index = heightList.indexOf(min);
liList[index].appendChild(img);
heightList[index] += img.height;
if (bodyWidth !== document.body.clientWidth) resize();
//懒加载:每次只加载可视窗口高度*3高的内容
if(document.body.clientHeight-document.documentElement.scrollTop>document.documentElement.clientHeight*3) return;
//将改变src的代码放到一个新函数reload中,方便懒加载,在滚动条滚动时重新触发
reload();
}
function reload(){
n++;
if (n > 79) return;
// 因为在新的函数中调用,this指向发生改变,可以使用箭头函数改变this指向,也可以将img变量设置成全局变量,方便调用
//此处我将img变量设置成全局变量
// this.src = `./imgs/${n}-.jpg`;
imgs.src = `./imgs/${n}-.jpg`;
}
function resize() {
bodyWidth = document.body.clientWidth;
width = (bodyWidth - GAP * (COL - 1)) / COL;
var lis = Array.from(document.querySelector("ul").children);
lis.forEach((item, index) => {
item.style.width = width + "px";
var height = 0;
for (var i = 0; i < item.children.length; i++) {
item.children[i].style.width = width + "px";
height += item.children[i].height;
}
heightList[index] = height;
})
}
//滚动条滚动时,继续加载图片
function scrollHandler(e){
if(document.body.clientHeight-document.documentElement.scrollTop>document.documentElement.clientHeight*2){
reload();
}
}
</script>
</body>
</html>