задний план:
Поскольку реализация веб-страницы является однопоточной, страница представляет собой состояние блокировки во время выполнения JS. Поэтому, если объем обрабатываемых данных слишком велик, процесс усложняется, и страницы могут вызвать ошибку page. Традиционное отображение данных осуществляется в виде разбиения на страницы, но эффект разбиения на страницы не очень хорош, вам нужно вручную щелкнуть следующую страницу, чтобы увидеть больше контента. На многих веб-сайтах используется неограниченный режим подкачки, то есть окно веб-страницы появляется в нижней части содержимого, следующая часть загружается автоматически ...
принцип:
实现无限分页的过程大致如下:
1 视窗滚动到底部;
2 触发加载,添加到现有内容的后面。
因此,可能会出现两种情况:
1 当页面的内容很少,没有出现滚动条;触发加载页面事件,直到加载到满足条件时停止加载;
2 当页面的内容很多,出现了滚动条
Поговорим о первом традиционном методе
концепции для понимания
scrollHeight — высота реального контента;
clientHeight легко понять, это высота окна, то есть высота содержимого, которое мы видим в браузере;
scrollTop — это скрытая часть окна выше.
Идеи реализации:
1 Если реальный контент меньше высоты окна просмотра, загружайте его до тех пор, пока он не выйдет за пределы окна просмотра.
2 Если он выходит за пределы окна, оцените, меньше ли расстояние до скрытой части ниже определенного значения, и если да, то запустите загрузку. (т.е. прокручивается вниз)
// 触发条件函数
function lowEnough(){
var pageHeight = Math.max(document.body.scrollHeight,document.body.offsetHeight);
var viewportHeight = window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight || 0;
var scrollHeight = window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop || 0;
return pageHeight - viewportHeight - scrollHeight < 20; // 通过 真实内容高度 - 视窗高度 - 上面隐藏的高度 < 20,作为加载的触发条件
}
Второй метод: IntersectionObserver (простой, но требует браузеров)
1. API
Его использование очень просто.
var io = new IntersectionObserver(callback, option);
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
В приведенном выше коде IntersectionObserver является конструктором, изначально предоставленным браузером, и принимает два параметра: callback — это функция обратного вызова при изменении видимости, а option — объект конфигурации (этот параметр является необязательным).
Возвращаемое значение конструктора является экземпляром наблюдателя. Метод наблюдения экземпляра может указать, за каким узлом DOM следует наблюдать.
Во-вторых, параметр обратного вызова
Когда видимость целевого элемента изменяется, вызывается функция обратного вызова наблюдателя.
Обратный вызов обычно срабатывает дважды. Один раз, когда целевой элемент только что вошел в область просмотра (начиная с видимого), и один раз, когда он полностью покинул область просмотра (начало с невидимого).
var io = new IntersectionObserver(
entries => {
console.log(entries);
}
);
В приведенном выше коде функция обратного вызова написана как функция стрелки. Параметр (записи) функции обратного вызова представляет собой массив, каждый элемент которого является объектом IntersectionObserverEntry. Например, если видимость двух наблюдаемых объектов изменится одновременно, массив записей будет состоять из двух элементов.
3. Объект IntersectionObserverEntry
Объект InterseiCebServerentry предоставляет информацию о целевом элементе и имеет в общей сложности шесть свойств.
Смысл каждого свойства следующий.
time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
target:被观察的目标元素,是一个 DOM 节点对象
rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
boundingClientRect:目标元素的矩形区域的信息
intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
На изображении выше серые горизонтальные прямоугольники представляют окно просмотра, а темно-красные области представляют четыре наблюдаемых целевых элемента. Были отмечены соответствующие диаграммы отношения пересечений.
Пример:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.img-area{width: 500px;height: 500px; margin: 0 auto;}
.my-photo{width:500px; height: 300px}
</style>
</head>
<body>
<div id="container">
<div class="img-area"><img class="my-photo" alt="loading" src="./img/1.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" src="./img/2.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" src="./img/3.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" src="./img/4.jpg" /></div>
</div>
<div class="scrollerFooter1">
没有内容了
</div>
<script>
function infinityScroll(footerNode, callback) {
var observer = new IntersectionObserver(function(changes) {
// 注意intersectionRatio这个属性值的判断
if (changes[0].intersectionRatio <= 0) return;
callback();
});
observer.observe(document.querySelector(footerNode));
}
infinityScroll('.scrollerFooter1', function() {
for (var i = 0; i< 3; i++) {
document.getElementById('container').appendChild(document.getElementById('container').firstChild)
}
});
</script>
</body>
</html>
Конечно, ленивая загрузка также может быть реализована:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.img-area{width: 500px;height: 500px; margin: 0 auto;}
.my-photo{width:500px; height: 300px}
</style>
</head>
<body>
<div class="container">
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/1.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/2.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/3.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/4.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/5.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/1.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/2.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/3.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/4.jpg" /></div>
<div class="img-area"><img class="my-photo" alt="loading" data-src="./img/5.jpg" /></div>
</div>
<script>
function lazyLoad(imgClassName) {
const imgList = Array.from(document.querySelectorAll(imgClassName));
var io = new IntersectionObserver(function (ioes) {
ioes.forEach(function (ioe) {
var el = ioe.target;
var intersectionRatio = ioe.intersectionRatio;
if (intersectionRatio > 0 && intersectionRatio <= 1) {
if (!el.src) {
el.src = el.dataset.src
}
}
})
});
imgList.forEach(function(item) {
io.observe(item)
});
}
lazyLoad('.my-photo');
</script>
</body>
</html>
Наконец, давайте поговорим о поддержке каждого браузера для этого API, будьте осторожны, прежде чем использовать его:
Кроме того, часть текста в тексте обращается к великому богу - Жуань Ифэну.статья