Попробуйте лениво загрузить картинку самостоятельно...
Демонстрационный адрес:axuebin.com/lazyload
Адрес источника:GitHub.com/Axue Temple/Pull…
Все фото сделаны мной~
ленивая загрузка
Что такое ленивая загрузка
Отложенная загрузка на самом деле является отложенной загрузкой, то есть способом оптимизации производительности веб-страниц, например, при посещении страницы сначала отображаются изображения в видимой области, а не загружаются все изображения одновременно, а запрос изображения отправляется, когда его необходимо отобразить.Избегайте загрузки слишком большого количества ресурсов при открытии веб-страниц.
Когда использовать ленивую загрузку
Когда странице необходимо загрузить много изображений одновременно, часто необходимо использовать отложенную загрузку.
Принцип ленивой загрузки
Мы все знаем, что в HTML<img>
Метка — это изображение, представляющее документ. . Глупости сказал. .
<img>
Тег имеет атрибут, которыйsrc
, используемый для представления URL-адреса изображения, когда значение этого атрибута не пусто, браузер отправит запрос в соответствии с этим значением. если нетsrc
атрибут, запрос не будет отправлен.
Эм? Кажется, это можно использовать?
я не устанавливаюsrc
, настроить его при необходимости?
Хорошо, вот это.
мы не даем<img>
настраиватьsrc
, поместите реальный URL изображения в другой атрибутdata-src
, когда это необходимо, то есть до того, как картинка попадет в видимую область, выньте URL-адрес и поместите его в полеsrc
середина.
выполнить
HTML-структура
<div class="container">
<div class="img-area">
<img class="my-photo" alt="loading" data-src="./img/img1.png">
</div>
<div class="img-area">
<img class="my-photo" alt="loading" data-src="./img/img2.png">
</div>
<div class="img-area">
<img class="my-photo" alt="loading" data-src="./img/img3.png">
</div>
<div class="img-area">
<img class="my-photo" alt="loading" data-src="./img/img4.png">
</div>
<div class="img-area">
<img class="my-photo" alt="loading" data-src="./img/img5.png">
</div>
</div>
Поближе,<img>
На данный момент ярлык отсутствуетsrc
атрибут, толькоalt
а такжеdata-src
Атрибуты.
Атрибут alt является обязательным атрибутом, который указывает альтернативный текст, когда изображение не может быть отображено.
глобальные атрибуты data-*: формируют класс атрибутов с именами пользовательских атрибутов данных, доступ к которым можно получить черезHTMLElement.dataset
посетить.
Как узнать, находится ли элемент в видимой области
метод первый
Много видел этого метода в интернете, и немного записал.
- пройти через
document.documentElement.clientHeight
Получить высоту видимого окна на экране - пройти через
element.offsetTop
Получить расстояние элемента относительно верхней части документа - пройти через
document.documentElement.scrollTop
Получить расстояние между верхней частью окна браузера и верхней частью документа, то есть расстояние, на которое прокручивается полоса прокрутки.
Затем оцените, установлено ли ②-③
Метод 2 getBoundingClientRect
пройти черезgetBoundingClientRect()
метод для получения размера и положения элемента, как описано в MDN:
The Element.getBoundingClientRect() method returns the size of an element and its position relative to the viewport.
Этот метод возвращаетClientRect
изDOMRect
объект, в том числеtop
,right
,botton
,left
,width
,height
Эти значения.
На MDN есть такая картинка:
Видно, что возвращаемая позиция элемента относится к верхнему левому углу, а не к полю.
Давайте подумаем, при каких обстоятельствах картинка попадает в видимую область.
Предположениеconst bound = el.getBoundingClientRect();
представлять расстояние от изображения до верхней части видимой области;
рядомconst clientHeight = window.innerHeight;
чтобы указать высоту видимой области.
Когда полоса прокрутки прокручивается вниз,bound.top
будет становиться все меньше и меньше, то есть расстояние от изображения до вершины видимой области становится все меньше и меньше.bound.top===clientHeight
, верхний край изображения должен быть критической точкой на нижнем краю видимой области, и если вы прокрутите немного дальше, изображение войдет в видимую область.
То есть вbound.top<=clientHeight
, изображение находится в пределах видимой области.
Мы судим так:
function isInSight(el) {
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
//如果只考虑向下滚动加载
//const clientWidth = window.innerWeight;
return bound.top <= clientHeight + 100;
}
Здесь +100 за раннюю загрузку.
загрузить изображение
При открытии страницы необходимо проверить все изображения, находятся ли они в видимой области, и если да, то они будут загружены.
function checkImgs() {
const imgs = document.querySelectorAll('.my-photo');
Array.from(imgs).forEach(el => {
if (isInSight(el)) {
loadImg(el);
}
})
}
function loadImg(el) {
if (!el.src) {
const source = el.dataset.src;
el.src = source;
}
}
Здесь должна быть оптимизация. Установите идентификатор для определения индекса загруженного изображения. Когда полоса прокрутки прокручивается, вам не нужно проходить все изображения, просто проходить незагруженные изображения.
регулирование функции
В частых операциях DOM, таких как прокрутка полосы прокрутки, всегда упоминается «регулирование функций, устранение дребезга функций».
Так называемое регулирование функции предназначено для предотвращения слишком частого выполнения функции и уменьшения количества слишком быстрых вызовов для регулирования.
Основные шаги:
- Получить метку времени первого инициированного события
- Получить метку времени второго триггерного события
- Выполнить событие, если разница во времени больше определенного порога, затем сбросить в первый раз
function throttle(fn, mustRun = 500) {
const timer = null;
let previous = null;
return function() {
const now = new Date();
const context = this;
const args = arguments;
if (!previous){
previous = 0;
}
const remaining = now - previous;
if (mustRun && remaining >= mustRun) {
fn.apply(context, args);
previous = now;
}
}
}
здесьmustRun
интервал времени между обращениями к функции, независимо от того, как частоfn
,Толькоremaining>=mustRun
Времяfn
быть казненным.
эксперимент
когда страница открывается
Видно, что в это время грузятся только img1 и img2, а остальные img запросы не отправляли.Взгляните на браузер в это время.
Первая картинка представлена полностью, а вторая картинка только что вошла в видимую область, а последнюю не видно~
когда страница прокручивается
Когда я прокручиваю вниз, браузер выглядит так
В этот момент второе изображение полностью отображается, а третье изображение немного показывается.В это время давайте посмотрим на запрос.
Запрос img3 отправлен, но последующий запрос еще не отправлен~
когда все загружено
Когда полоса прокрутки прокрутится вниз, все запросы должны быть выданы, как показано на рисунке
полная демонстрация
О вот:axuebin.com/lazyload
возобновить
Метод 3 IntersectionObserver
После того, как большой парень напомнил мне, я нашел этот метод
Сначала прикрепите ссылку:
jjc сильно:GitHub.com/просто Java от/он…
Руан Ифэн великолепен:Вууху. Руань Ифэн.com/blog/2016/1…
Эскиз API для наблюдателей за пересечениями:GitHub.com/WICG/inters…
IntersectionObserver
Может автоматически наблюдать, находится ли элемент внутри области просмотра.
var io = new IntersectionObserver(callback, option);
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
Аргументом обратного вызова является массив, каждый массив представляет собойIntersectionObserverEntry
объекта, включая следующие свойства:
Атрибуты | описывать |
---|---|
time | Время изменения видимости в миллисекундах |
rootBounds | То же, что и возвращаемое значение метода getBoundingClientRect(). |
boundingClientRect | Информация о прямоугольной области целевого элемента |
intersectionRect | Информация о области пересечения целевого элемента и области просмотра (или корневого элемента) |
intersectionRatio | Отношение видимости целевого элемента, то есть отношение пересеченияRect к boundingClientRect, равно 1, когда он полностью виден, и меньше или равно 0, когда он полностью невидим. |
target | Наблюдаемый целевой элемент является объектом узла DOM. |
нам нужно использоватьintersectionRatio
Чтобы определить, находится ли это в видимой области, когдаintersectionRatio > 0 && intersectionRatio <= 1
то есть в пределах видимой области.
код
function checkImgs() {
const imgs = Array.from(document.querySelectorAll(".my-photo"));
imgs.forEach(item => io.observe(item));
}
function loadImg(el) {
if (!el.src) {
const source = el.dataset.src;
el.src = source;
}
}
const io = new IntersectionObserver(ioes => {
ioes.forEach(ioe => {
const el = ioe.target;
const intersectionRatio = ioe.intersectionRatio;
if (intersectionRatio > 0 && intersectionRatio <= 1) {
loadImg(el);
}
el.onload = el.onerror = () => io.unobserve(el);
});
});