Нативный JS реализует простейшую ленивую загрузку изображений.

JavaScript

Попробуйте лениво загрузить картинку самостоятельно...

Демонстрационный адрес: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посетить.

Как узнать, находится ли элемент в видимой области

метод первый

Много видел этого метода в интернете, и немного записал.

  1. пройти черезdocument.documentElement.clientHeightПолучить высоту видимого окна на экране
  2. пройти черезelement.offsetTopПолучить расстояние элемента относительно верхней части документа
  3. пройти через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, таких как прокрутка полосы прокрутки, всегда упоминается «регулирование функций, устранение дребезга функций».

Так называемое регулирование функции предназначено для предотвращения слишком частого выполнения функции и уменьшения количества слишком быстрых вызовов для регулирования.

Основные шаги:

  1. Получить метку времени первого инициированного события
  2. Получить метку времени второго триггерного события
  3. Выполнить событие, если разница во времени больше определенного порога, затем сбросить в первый раз
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);
  });
});