14、js实现流式布局及重排列、懒加载。
先来看看效果
流式布局实现思路:
其实流式布局咱可以参考百度的图片搜索。其实原理几个固定宽度的div列表,然后将子div或者img插入列表
具体插入哪个列表呢? 可以通过比较列表的高度,将子元素插入到列表高度最小的一个列表。
难点:
其实没什么难点,获取数据,然后插入到列表中
懒加载实现思路
就是根据滚动条的高度来判断是否到达底部。然后继续加载数据
难点:
- 获取滚动条位置
document.documentElement.scrollTop || document.body.scrollTop
- 获取滚动条的总高度
- HTMLELement.scrollHeight
- 获取页面总高度
document.documentElement.clientHeight|| document.body.clientHeight
- 加载数据
- 按照流式布局加载子元素的方法加进去就好了
优化点:
- 可以不必在滚动条完全到达底部在加载数据,可以在距离底部适当高度的时候就加载数据,可以让用户少些等待 时间
流式布局重排列
重排列? 就是当窗口大小发生变化的时候将流式布局重新进行布局。
实现思路:可以将所有子元素存在一个数组中,然后监听窗口大小变化,达到一定变化程度的时候就进行重排列。(需要动态判断流式布局列的数量)
具体代码如下
<!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>流式布局及懒加载</title>
<style>
*{
margin: 0;
padding: 0;
}
.container{
display: flex;
justify-content: space-around;
/* 使每个容器保持自身的高度 */
align-items: flex-start;
}
.default-width{
width: 180px;
margin: 0 5px;
color: white;
text-align: center;
/* line-height: 56px; */
font-size: 20px;
/* border: 1px solid black; */
}
.default-width div{
margin: 10px 0;
}
.btn{
padding: 4px 8px;
position: fixed;
left: 50%;
}
.loading{
/* display: none; */
height: 50px;
border: 1px solid black;
text-align: center;
line-height: 50px;
}
.load{
display: block;
background-color: red;
height: 5px;
width: 5px;
}
</style>
</head>
<body>
<div class="container">
</div>
<script>
var body = document.body
var container = document.querySelector(".container");
// child's id
var id = 1
// 存入多个列表
var lists = [];
// 所有列表的子元素
var childrens = []
// 将list添加至list
var len = childrens.length
// 初始化
initLists()
generateChild(60)
// 计算list个数
function initLists(){
// 初始化前首先获取屏幕宽高 生成对应个list
var initWidth = document.documentElement.clientWidth || document.body.clientWidth
console.log('initWidth', initWidth);
// 判断生成多少个list, list width is 180px ,left and rignt margin is 5px
let n = Math.floor(initWidth / (180 + 10))
// 多余宽度
let bodyPadding = (initWidth - n * (180 + 10))/2
body.style.padding = `0 ${
bodyPadding}px`
// 优化
// if(initWidth < 800) body.style.minWidth = initWidth + "px"
console.log('min-width', body.style.minWidth);
// 生成list-div
for (let i = 0; i < n; i++) {
let div = document.createElement("div");
div.className = "default-width"
// div.innerText = i + 1
container.append(div)
lists.push(div)
}
}
// 移除list
function removeLists(){
for (let k = 0; k < lists.length; k++) {
container.removeChild(lists[k])
}
}
// 绑定窗口大小改变事件
window.onresize = debounce(()=>{
console.log("尺寸改变了, 子元素数量", len);
// 移除list DOM
removeLists()
// 清除lists 数组
lists = []
// 重新计算list
initLists()
// 子元素重排列
generateChild(0)
}, 300)
// 监听滚动条
window.onscroll = throttle(verdictScroll, 300)
// 判断是否滚动条是否在最底部
function verdictScroll(){
// 滚动条总高度
let scrollHeight = container.scrollHeight
// console.log('总高度', scrollHeight);
// 兼容获取scrollTop document.documentElement.scrollTop || document.body.scrollTop
// 获取scroll当前的位置
let scrollTop = Math.ceil(document.documentElement.scrollTop || document.body.scrollTop)
// console.log('当前高度', scrollTop);
let clientHeight = document.documentElement.clientHeight || document.body.clientHeight
// console.log('clientHeight', clientHeight);
// + 550 最大高度 提前加载数据
if(clientHeight + scrollTop + 550 >= scrollHeight){
console.log("滚动条触发新增");
setTimeout(() => {
let co = lists.length * 10
generateChild(co)
}, Math.random() * 100);
}
}
// 节流函数
function throttle(cb, timeout){
let flag = false
return function(){
if(flag) return
flag = true
setTimeout(() => {
cb()
flag = false
}, timeout);
}
}
//防抖
function debounce(cb, timeout){
let timer = null
return function(){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
cb()
}, timeout);
}
}
// 生成child 并添加至list
function generateChild(count = 1){
for (let i = 0; i < count; i++) {
// 生成child
let child = document.createElement("div")
// 获取随机样式
let {
h,r,g,b} = randomChildStyle()
// 添加样式
child.style.height = h + "px"
child.style.backgroundColor = `rgb(${
r}, ${
g}, ${
b})`
child.innerText = "id:" + id++
// 将元素存入childrens
childrens.push(child)
// 存入某个元素之前
// minHeightOuter.insertBefore(child, innerLoading)
}
len = childrens.length
// 将childrens推入list
let j
if(count !== 0){
for ( j = len - count; j < len; j++) {
// 获取最小高度div
let minHeightOuter = getMinHeightOuter(lists)
// 添加至dom元素
minHeightOuter.append(childrens[j])
}
}else{
// 如果为0 则进行重排列
for ( j = 0; j < len; j++) {
// 获取最小高度div
let minHeightOuter = getMinHeightOuter(lists)
// 添加至dom元素
minHeightOuter.append(childrens[j])
}
console.log('重排列');
}
console.log(`新增${
count}个`);
}
// 获取最小高度div 返回最小Height 的 DOM
function getMinHeightOuter(doms){
let minHeightDom = null
for (let i = 0; i < doms.length; i++) {
// 这里通过div的style获取height是获取不到的 因为div的style属性为空
// heightArr[i] = doms[i].offsetHeight
if(minHeightDom !== null){
// 寻找高度最低的那个outer
if(minHeightDom.offsetHeight > doms[i].offsetHeight){
minHeightDom = doms[i]
}
}else{
// 初始化 minHeightDom
minHeightDom = doms[i]
}
}
return minHeightDom
}
// 获取div随机样式 颜色、高度
function randomChildStyle(){
let h = Math.random() * 200 + 50
let r = Math.random() * 255
let g = Math.random() * 255
let b = Math.random() * 255
return {
h,r,g,b
}
}
</script>
</body>
</html>