Ленивая загрузка изображений очень важна, особенно для мобильных пользователей.
Теоретически механизм ленивой загрузки изображений прост, но на практике есть много деталей, на которые следует обратить внимание. Кроме того, есть несколько различных вариантов использования, которые выигрывают от отложенной загрузки. Во-первых, давайте рассмотрим ленивую загрузку встроенных изображений в HTML.
Ленивая загрузка — это метод задержки загрузки некритических ресурсов при загрузке страницы, и эти некритические ресурсы загружаются только при необходимости. Что касается изображений, «некритическое» обычно означает «за кадром».
Недавно я работаю над мобильным комическим приложением (id.mangaya.mobi), там задействовано много картинок, если картинки не обработать дополнительно, то это будет не очень удобно, и соответственно будет снижен балл маяка.
Сцены
Есть в основном два сценария.
Заинтересованные студенты могут просмотретьreact-progressive-lazy-image, очень проста в использовании!
Senario 1: изображение задерживается до тех пор, пока оно не начнет загружаться в окне просмотра окна.
Senario 2: пользователи смотрят комиксы и должны загружать комиксы один за другим.
принцип
Технология отложенной загрузки изображения в основном определяет, загружается ли ресурс изображения, отслеживая, появляется ли контейнер ресурса изображения в области окна просмотра.
Затем суть реализации технологии ленивой загрузки изображений заключается в том, как определить, что элемент находится в пределах области просмотра.
упражняться
Итак, как этого достичь?
getBoundingClientRect()
Возвращаемое значение — это объект DOMRect, представляющий собой объединение прямоугольников, возвращаемых элементом getClientRects(), который является границей CSS, связанной с элементом. В результате он содержит весь элемент с минимальным прямоугольником, доступным только для чтения, со свойствами левого, верхнего, правого, нижнего, x, y, ширины и высоты, описывающими общую ограничивающую рамку в пикселях. За исключением свойств ширины и высоты левого верхнего угла области просмотра относительно левого верхнего угла области просмотра.
//https://gomakethings.com/how-to-test-if-an-element-is-in-the-viewport-with-vanilla-javascript/
export const elementIsInsideViewport = el => {
const bounding = el.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <=
(window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <=
(window.innerWidth || document.documentElement.clientWidth)
);
};
Вы можете комбинировать события window.onScroll и window.onResize и дроссель, чтобы реализовать оценку элемента img.
document.addEventListener("DOMContentLoaded", function() {
let lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
let active = false;
const lazyLoad = function() {
if (active === false) {
active = true;
setTimeout(function() {
lazyImages.forEach(function(lazyImage) {
if ((lazyImage.getBoundingClientRect().top <= window.innerHeight && lazyImage.getBoundingClientRect().bottom >= 0) && getComputedStyle(lazyImage).display !== "none") {
lazyImage.src = lazyImage.dataset.src;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.classList.remove("lazy");
lazyImages = lazyImages.filter(function(image) {
return image !== lazyImage;
});
if (lazyImages.length === 0) {
document.removeEventListener("scroll", lazyLoad);
window.removeEventListener("resize", lazyLoad);
window.removeEventListener("orientationchange", lazyLoad);
}
}
});
active = false;
}, 200);
}
};
document.addEventListener("scroll", lazyLoad);
window.addEventListener("resize", lazyLoad);
window.addEventListener("orientationchange", lazyLoad);
});
Этот код, чтобы проверить, есть ли какой-либо элемент в IMG Viewport IMG.Lazy, используйте GetBoundingClientRect в обработчике событий прокрутки. Вызов Settimeout Использование обработки задержки, обработка, включающая активную переменную состояния, функцию для ограничения вызова. Загрузка задержки изображения, то эти элементы удаляются из элементов в массиве. Когда элемент длины массива достигает нуля, обработчик обработчика события прокрутки сразу удален.
Хотя этот код будет нормально работать практически в любом браузере, существует потенциальная проблема с производительностью, когда повторные вызовы setTimeout могут быть расточительными, даже если код внутри ограничен, они все равно будут выполняться. В этом примере проверка запускается каждые 200 миллисекунд при прокрутке документа или изменении размера окна, независимо от того, есть ли изображение в области просмотра. Кроме того, утомительная работа по отслеживанию количества элементов, которые не были загружены отложенно, и отвязка обработчиков событий прокрутки будет выполняться разработчиком.
использование наилучшей практикиIntersection Observer
Этот метод очень прост, вам нужно только сгенерировать IntersectionObserver для элемента и отслеживать элемент, а затем судить о соотношении IntersectionRatio элемента в отслеживаемом обратном вызове для достижения требуемого. Это основной код.
componentDidMount() {
const { src, needLazyUtilInViewPort, canLoadRightNow } = this.props;
if (needLazyUtilInViewPort) {
//https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
try {
const node = ReactDOM.findDOMNode(this);
this.observer = new IntersectionObserver(this.insideViewportCb);
this.observer.observe(node);
} catch (err) {
console.log("err in finding node", err);
}
} else {
if (canLoadRightNow) {
this.loadImage(src);
}
}
}
insideViewportCb(entries) {
entries.forEach(element => {
//在viewport里面
if (element.intersectionRatio >0) {
this.loadImage(this.props.src);
}
});
}
Однако недостатком Intersection Observer является то, что хотяХорошая поддержка между браузерами, но не все браузеры его поддерживают. Для браузеров, которые не поддерживают Intersection Observer, вы можете использоватьpolyfill, или, как описано в приведенном выше коде, определить, доступен ли Intersection Observer, и вернуться к более совместимому старому методу, если это не так.
Что касается последовательной загрузки изображения списка, необходимо только уведомить родительский компонент, что следующее изображение может быть загружено в каждом обратном вызове изображения. В общем, как getBoundingClientRect, так и Intersection Observer могут обеспечить ленивую загрузку изображений, но если getBoundingClientRect использует другие события onScroll на текущей странице, будут проблемы, такие как застревание и не может скользить очень плавно, в то время как Intersection Observer очень прост и удобен в использовании .
Компоненты ленивой загрузки изображений и последовательной загрузки изображений списка имеют открытый исходный код~!
Заинтересованные студенты могут просмотретьreact-progressive-lazy-image, очень проста в использовании!