infinite-scroll.js
js
const observerOptions = {
threshold: [0, .25, .5, .75, 1]
}
const DETECT_RATIO = .5
const mountInfiniteScroll = (options) => {
const {
detector,
detectListener,
detectRatio = DETECT_RATIO,
} = options
const observer = (elem) => {
const [{intersectionRatio, isIntersecting}] = elem
if (intersectionRatio >= detectRatio && isIntersecting) {
detectListener()
}
}
const intersectionObserver = new IntersectionObserver(observer, observerOptions)
intersectionObserver.observe(detector);
}
index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="wrapper">
<div class="detector"></div>
</div>
<script src="infinite-scroll.js"></script>
<script src="script.js"></script>
</body>
</html>
script.js
js
const STEP = 10
let currentNum = 0
const assign = (obj, ...objs) => Object.assign(obj, ...objs)
const findElem = selector => document.querySelector(selector)
const addElems = () => {
const wrapper = findElem('.wrapper')
const detector = findElem('.detector')
const frag = document.createDocumentFragment()
const liTag = assign(document.createElement('div'), {
className: 'box'
})
Array
.from({length: STEP})
.map((v, i) => {
const textContent = currentNum + i + 1
return assign(liTag.cloneNode(), {textContent})
})
.forEach(elem => {
frag.appendChild(elem)
})
wrapper.insertBefore(frag, detector)
currentNum += STEP
}
window.onload = () => {
addElems()
mountInfiniteScroll({
detector: findElem('.detector'),
detectListener: addElems,
detectRatio: .5,
})
}
style.css
css
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%
}
.wrapper {
position: relative;
width: 300px;
height: 600px;
border: solid 3px #999;
overflow-y: auto
}
.box {
width: 100%;
height: 100px;
float: left;
box-sizing: border-box;
padding: 10px;
border: solid 1px #999
}
.detector {
width: 100%;
height: 50px;
float: left;
background-color: #f00
}