От автора: изображения занимают значительный процент доступного пространства вашего сайта. Некоторые из них размещаются ниже первого сгиба, что означает, что они не видны сразу, когда посетитель заходит на сайт. Что бы увидеть это изображение посетитель должен прокрутить страницу вниз. Было бы здорово, если бы могли выводить сразу только изображения до первого сгиба, а остальные загружать позже. Да, отложенная загрузка изображений вполне реальна. Об этом и пойдет речь в данной статье. Подобную функцию вы должны быть видеть на Medium.
Я написал статью о том, как использовать API-интерфейс Intersection Observer для реализации бесконечной прокрутки в React. Если мы можем реализовать бесконечную прокрутку, мы также должны иметь возможность отложено загружать изображения. Оба аспекта связаны с тем же принципом отложенной загрузки. Вам стоит ознакомиться с Введение той стать, чтобы понять, как работает Observer.
Рассмотрение источника изображения
Пример, который мы рассмотрим в этой статье, будет содержать 5 или более изображений, но для каждого мы будем рассматривать такие аспекты:
<img src="http://res.cloudinary.com/christekh/image/upload/c_scale,h_3,w_5/v1505391130/wynand-van-poortvliet-364366_gsvyby.jpg" data-src="http://res.cloudinary.com/christekh/image/upload/c_scale,h_300,w_500/v1505391130/wynand-van-poortvliet-364366_gsvyby.jpg" >
Каждый тег будет содержать атрибут data-src и src:
data-src — это фактический URL-адрес изображения (width: 500px), который мы хотим отобразить.
src содержит то же изображение в очень маленьком разрешении (width: 5px). Это изображение будет растянуто, чтобы заполнить пространство и создать эффект размытости при загрузке реального изображения. Меньшее изображение в 10 раз меньше, поэтому, если все остальное будет в порядке, оно будет загружаться быстрее (в 10 раз).
Изображения хранятся на сервере Cloudinary, что упрощает настройку размера изображений через URL (h_300, w_500 или h_3, w_5).
Наблюдатель
Наблюдатель является экземпляром Intersection Observer. Мы создаем его и используете этот экземпляр для наблюдения за элементом DOM. Вы можете наблюдать, когда элемент входит в область просмотра:
const options = { rootMargin: '0px', threshold: 0.1 }; const observer = new IntersectionObserver(handleIntersection, options);
Экземпляр принимает обработчик и аргумент options. Обработчик — это функция, вызываемая при нахождении пересечения, при этом аргумент options определяет поведение наблюдателя. В этом случае мы хотим, чтобы обработчик вызывался, как только изображение попадает в окно просмотра (threshold: 0.1). Вы можете использовать наблюдатель для наблюдения за всеми изображениями на странице:
const images = document.querySelectorAll('img'); images.forEach(img => { observer.observe(img); })
Обработка пересечения
Мы использовали метод для обработчика, но не определяли его. Естественно, это будет выдавать ошибку. Давайте создадим обработчик выше экземпляра:
const handleIntersection = (entries, observer) => { entries.forEach(entry => { if(entry.intersectionRatio > 0) { loadImage(entry.target) } }) }
Метод вызывается API с массивом entries и экземпляром observer. entries хранят экземпляр всех соответствующих элементов DOM (в нашем случае img). Если найдено соответствие, мы вызываем с элементом loadImage. loadImage извлекает изображение, а затем устанавливает src изображения соответствующим образом:
const loadImage = (image) => { const src = image.dataset.src; fetchImage(src).then(() => { image.src = src; }) }
Он делает это, вызывая метод fetchImage со значением data-src. Когда возвращается фактическое изображение, он затем устанавливает значение image.src.
const fetchImage = (url) => { return new Promise((resolve, reject) => { const image = new Image(); image.src = url; image.onload = resolve; image.onerror = reject; }); }
Рассмотрение других аспектов
Для улучшения опыта взаимодействия вы также можете добавить эффект к изображению при переходе от размытого к четкому. Это делает его более привлекательным, если время загрузки воспринимается как более медленное.
Обратите внимание, что Intersection Observer не поддерживается надлежащим образом во всех браузерах, поэтому вы можете использовать полифилл или автоматически загружать изображения после загрузки страницы:
if ('IntersectionObserver' in window) { // Observer code const observer = new IntersectionObserver(handleIntersection, options); } else { // IO is not supported. // Just load all the images Array.from(images).forEach(image => loadImage(image)); }
Заключение
В 2018 году и в будущем мы будем стремиться предоставить пользователям лучший опыт взаимодействия. Производительность — это то, что должно нас беспокоить, потому что конкуренты не дремлют, и ваши пользователи будут уходить, если время загрузки увеличится или они получат плохой опыт. С помощью прогрессивных изображений вы можете существенно сократить время, затрачиваемое на загрузку ресурсов.
Автор: Chris Nwamba
Источник: https://scotch.io/
Редакция: Команда webformyself.