html:
<div id="scroll-view">
<div class="container"></div>
<!-- 结尾加载区域 -->
<div id="loading-block"></div>
</div>
css:
#scroll-view {
width: 800px;
height: 800px;
overflow-y: auto;
background: #000;
}
.container {
position: relative;
width: 100%;
}
.container img {
position: absolute;
}
#loading-block {
width: 100%;
height: 50px;
line-height: 50px;
font-size: 18px;
text-align: center;
color: #fff;
}
js:
let loadFinish = false // 图片是否加载完毕
// 创建元素是否进入可视区域实例
const obs = new IntersectionObserver((e) => {
const isVisible = e[0].isIntersecting
if (isVisible) {
loadMore()
}
if (loadFinish) {
// 加载完毕,移除监听
obs.unobserve(document.getElementById('loading-block'))
// 可以移除加载区域
document.getElementById('scroll-view').removeChild(document.getElementById('loading-block'))
}
})
obs.observe(document.getElementById('loading-block'))
const option = { column: 4, space: 10 }
/**
* 根据外层盒子容器计算出每个图片的宽度以及间隔
* @param {HTMLElement} dom 外层容器
* @param {object} option
* @param {number | undefined} option.column 需要几列展示
* @param {number | undefined} option.space 图片间距
* @param {number | undefined} option.width 图片宽度
*/
function calc(dom, option) {
const parentWidth = dom.getBoundingClientRect().width
let { column, space, width } = option
if (column) {
// 给定列数和父级,求每张图片的宽度
width = (parentWidth - (column + 1) * space) / column
} else if (width && space) {
// 给定图片宽度和父级dom,求可以分几列和间隔
column = Math.floor(parentWidth / width)
space = (parentWidth - column * width) / column + 1
}
return { column, space, width }
}
// 为图片设置位置
function setPos(dom, { column, space, width }) {
const pics = [...document.querySelectorAll('img')]
const nextTops = Array(column).fill(space) // 保存当前每一列的下一行距离顶部的值
pics.forEach((img) => {
img.setAttribute('width', width + 'px')
const minTop = Math.min.apply(null, nextTops) // 取最小值放置下一张图片
img.style.top = minTop + 'px'
const index = nextTops.indexOf(minTop)
// 图片原始宽高
const naturalWidth = img.naturalWidth
const naturalHeight = img.naturalHeight
// 图片实际高度
const realHeight = (width * naturalHeight) / naturalWidth
nextTops[index] += realHeight + space // 更新距离顶部的值
const x = (index + 1) * space + index * width
img.style.left = x + 'px' // 设置当前图片left值
})
// 设置外层容器的高度,防止塌陷
const max = Math.max.apply(null, nextTops)
dom.style.height = max + 'px'
}
// 加载更多图片
function loadMore() {
console.log('loadmore')
document.getElementById('loading-block').innerText = '加载中……'
let timeout = setTimeout(() => {
for (let index = 0; index < 20; index++) {
let img = document.createElement('img')
img.setAttribute(
'src',
index % 3 == 1
? './images/1.jpeg'
: index % 3 == 2
? './images/2.jpg'
: './images/3.jpeg'
)
document.querySelector('.container').appendChild(img)
}
init()
document.getElementById('loading-block').innerText = ''
// 加载完毕
if (document.querySelector('.container').childNodes.length >= 60) {
loadFinish = true
}
clearTimeout(timeout)
}, 1000)
}
function init() {
const dom = document.querySelector('.container')
const newOption = calc(dom, option)
const { column, space, width } = newOption
setPos(dom, { column, space, width })
}