Отложенная загрузка изображений с оптимизацией внешнего интерфейса

внешний интерфейс Vue.js

HTTP-запрос

Если вы изучали компьютерные сети, вы знаете, что мы просимnкартинкаhtml文件на самом деле отправитn+1запросы, т.к. парсинг в браузереhtmlвстретились, когдаsrc, запроситsrcсодержание позади.

Представьте, что если на нашей странице 1 000 000 изображений, то если задержка ожидания успешного ответа и загрузки этих изображений завершена, пользовательский опыт будет очень плохим.

Так можем ли мы сделать так, чтобы изображения загружались по запросу? Загружайте изображение, когда оно появляется в видимой области, вместо загрузки всего изображения в начале.

Ленивая загрузка изображения

шаблон:

<div @scroll="lazyLoad" ref="lazy">
    <img v-for="(src, index) in imgs" src="##" :dataSrc="src" :key="index">
    <!--more img-->
</div>

изменить источник изображения

Слушайте событие прокрутки самого внешнего div, перемещайтесь по изображению, чтобы определить положение изображения при запуске прокрутки, и отображайте его, если оно находится в видимой области.

loadImg() {
    var img = this.$refs.lazy.getElementsByClassName("lazyImg"); 
    // 已滚动高度+可视区高度
    var top = this.$refs.lazy.scrollTop + this.$refs.lazy.clientHeight;
    
    for(var i = 0; i < img.length; i++) {
        if(img[i].offsetTop <= top) {  // 在可视区内则显示图片
            img[i].src = img[i].getAttribute("datasrc");
        }
    }
},
lazyLoad() { 
    this.loadImg();
}

Выше реализована ленивая загрузка изображений, эта статья здесь, до свидания.

Мостовой мешок с бобами внезапно обнаружил серьезную проблему: он будет продолжать срабатывать во время процесса прокатки.lazyLoadСделайте обход и оцените изображение, тогда вы будете делать бесчисленное количество циклов for. Что еще ужаснее, так это то, что изменение src один раз отправит запрос. При прокрутке наш цикл for будет оценивать и изменять изображение запроса src каждый раз с самого начала, тогда количество запросов можно себе представить.

Функция защиты от тряски

Если обход постоянно запускается во время процесса прокрутки и событие мониторинга для определения того, находится ли изображение в видимой области, потребляет много производительности, здесь используется функция защиты от сотрясения: когда пользователь прекращает прокрутку, положение изображения равномерно пройдена и определена

debounce(fn) {
    // 函数防抖:用户停止操作之后触发
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
        fn();
    }, 1000);
}

Мы можем поместить метод загрузки изображения в debounce

lazyLoad() {
    this.debounce(this.loadImg);
}

Таким образом, когда пользователь прокручивает страницу, отпускание руки будет выполняться толькоloadImgДля обхода определить местоположение изображения.

Еще одна проблема: если пользователь прокручивает страницу снизу вверх и не отпускает, она не будет выполняться в течение этого периода.loadImg, а это значит, что картинки на странице отображаться не будут, что сильно влияет на пользовательский опыт

Оптимизация защиты от сотрясений

Мы оговариваем, что если пользовательская высота подтягивания больше 500 пикселей, картинка в видимой области будет автоматически загружена один раз, здесь мы используем oldScrollTop для записи последней высоты подтягивания.

lazyLoad() {
    // 如果上拉距离大于500px则自动加载
    if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
        this.loadImg();
        this.oldScrollTop = this.$refs.lazy.scrollTop; // 更新oldScrollTop
    } else {  // 如果向下拉但小于500px则防抖加载
        this.debounce(this.loadImg);
    }
}

раскрывающаяся оптимизация

Когда пользователь тянет вниз, нам не нужно выполнятьlazyLoad, потому что наше предыдущее изображение было загружено, поэтому мы можем изменить егоlazyLoad

lazyLoad() {
    // 如果上拉距离大于500px则自动加载
    if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
        this.loadImg();
        this.oldScrollTop = this.$refs.lazy.scrollTop;
    } else if(this.$refs.lazy.scrollTop - this.oldScrollTop < 0) {  // 如果向下拉则不做操作
        return ;
    } else {  // 如果向下拉但小于500px则防抖加载
        this.debounce(this.loadImg);
    }
}

Уменьшите количество обходов

Самые важные оптимизации уже сделаны, но мы также можем оптимизировать некоторые мелкие детали.loadImgВ методе изображение каждый раз просматривается и проверяется с индекса 0, но после того, как пользователь подтянется, часть изображений уже загружена, поэтому нет необходимости проверять снова.

Мы можем использовать переменнуюlenЗапишите последнее изображение после его последней загрузки, а затем измените его.loadImg

 loadImg() {
    var img = this.getImages(); 
    var top = this.$refs.lazy.scrollTop + window.screen.height;
    
    // 从len开始检查
    for(var i = this.len; i < img.length; i++) {
        if(img[i].offsetTop <= top) {
            img[i].src = img[i].getAttribute("datasrc");
            this.len = i;  // 更新len
        }
    }
}

Эпилог

Полная оптимизированная версия изображения загружается отложенно, и я инкапсулирую эту функцию в плагин vue.

Исходный код:vue-plugins

Библиотека плагинов будет постоянно обновляться, добро пожаловать на звездочку и форк~