Von der Theorie zur Codepraxis, zum Vorladen von Bildern und zum verzögerten Laden

Vorwort

Während des Entwicklungsprozesses laden wir oft Bilder vor und laden sie verzögert, um Seiten schnell zu laden und eine gute Benutzererfahrung zu erzielen. Wann man diese beiden verwendet, hängt von der Situation ab.

Vorladen

was ist vorladen

Laden Sie das Bild im Voraus, und nachdem der Ladevorgang abgeschlossen ist 缓存到本地, kann es direkt aus dem lokalen Cache gerendert werden, wenn der Benutzer es anzeigen muss, was eine gute Benutzererfahrung bietet.

Warum Vorladen verwenden?

用户更好的体验,减少等待的时间. Diese Praxis eigentlich 牺牲了服务器的性能换取了更好的用户体验.

Anwendungsbeispiel

Wie eine dedizierte Bild-Website wird für die Benutzererfahrung beim ersten Öffnen (kein langer weißer Bildschirm, ungeduldige Benutzer werden die Seite schließen) das Vorladen verwendet, aber es ist nicht alles vorinstalliert und ein Teil davon ist nicht vorinstalliert Beim Durchsuchen von Bildern auf der Website werden einige Bilder zu diesem Zeitpunkt leise geladen, sodass der Effekt einer nahtlosen Verbindung von Bildern erzielt werden kann und Sie sich überhaupt nicht langsam fühlen.

Es ist auch so, wenn Sie eine Gruppe von Bildern durchsuchen, wird Ihnen nur das erste Bild angezeigt, und Sie können Bilder in irgendeiner Form wechseln (klicken Sie auf die Schaltfläche), wenn Sie das erste Bild durchsuchen, tatsächlich eine ganze Gruppe von Bilder sind vorinstalliert. , warten Sie einfach, bis Sie wechseln.

Code vorladen

Vor der Verwendung von Preload

Es ist deutlich zu sehen, dass es eine Verzögerung gibt, wenn auf die Schaltfläche geklickt wird, und dann das Bild umgeschaltet wird, das das Bild anfordert (die Benutzererfahrung ist nicht gut), und das Bild wird tatsächlich vom Server angefordert und kein Cache wird genutzt.

动画.gif

Snipaste_2022-04-07_14-52-57.jpg

Vorspannung verwenden

Es ist ersichtlich, dass die Seite nach dem Klicken auf die Schaltfläche zum Wechseln schnell reagiert und sich nahtlos verbindet (die Benutzererfahrung ist ausgezeichnet), und das Betrachten des Bildes dann tatsächlich eine Pull-Anforderung ist, die den lokalen Cache verwendet. Warten Sie, bis es benötigt wird, rufen Sie den Cache auf und rendern Sie direkt aus dem Cache.

动画.gif

Snipaste_2022-04-07_14-54-53.jpg

Verwenden Sie JS zum Implementieren

<template>
  <div>
    <img :src="imgData[imgInd]" alt="" />
  </div>
  <button @click="onLeft">Left</button>
  <button @click="onRight">Right</button>
</template>

<script lang="ts">
import { ref } from "vue";
export default {
  name: "App",
  setup() {
    let imgData = ref<string[]>([
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/3.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/4.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/5.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/7.jpg",
    ]);
    // 预加载图片
    function preloadImg(srcArr: string[]): void {
      if (srcArr instanceof Array) {
        for (var i = 0; i < srcArr.length; i++) {
          var oImg = new Image();
          oImg.src = srcArr[i];
        }
      }
    }
    preloadImg(imgData.value);

    let imgInd = ref<number>(0);
    function onLeft() {
      imgInd.value - 1 < 0 ? 0 : --imgInd.value;
    }
    function onRight() {
      imgInd.value + 1 == imgData.value.length
        ? imgData.value.length - 1
        : ++imgInd.value;
    }
    return {
      onLeft,
      onRight,
      imgInd,
      imgData,
    };
  },
};
</script>
复制代码

CSS-Implementierung

  <div>
    <img :src="imgData[imgInd]" alt="" />
  </div>
  <button @click="onLeft">Left</button>
  <button @click="onRight">Right</button>
  <div class="img1"></div>
  <div class="img2"></div>
  <div class="img3"></div>
  <div class="img4"></div>
</template>

<script lang="ts">
import { ref } from "vue";
export default {
  name: "App",
  setup() {
    let imgData = ref<string[]>([
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/3.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/4.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/5.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/7.jpg",
    ]);
    
    let imgInd = ref<number>(0);
    function onLeft() {
      imgInd.value - 1 < 0 ? 0 : --imgInd.value;
    }
    function onRight() {
      imgInd.value + 1 == imgData.value.length
        ? imgData.value.length - 1
        : ++imgInd.value;
    }
    return {
      onLeft,
      onRight,
      imgInd,
      imgData,
    };
  },
};
</script>

<style scoped>
.img1 {
  height: 0px;
  width: 0px;
  background: url(https://cdn.jsdelivr.net/gh/lztnb/img@master/3.jpg);
}
.img2 {
  height: 0px;
  width: 0px;
  background: url(https://cdn.jsdelivr.net/gh/lztnb/img@master/4.jpg);
}
.img3 {
  height: 0px;
  width: 0px;
  background: url(https://cdn.jsdelivr.net/gh/lztnb/img@master/5.jpg);
}
.img4 {
  height: 0px;
  width: 0px;
  background: url(https://cdn.jsdelivr.net/gh/lztnb/img@master/5.jpg);
}
</style>
复制代码

faules Laden

Was ist lazy loading

Lazy Loading kann als Lazy Loading oder sogar No Loading bezeichnet werden. Ersetzen Sie beim Besuch einer Seite diese durch einen einheitlichen Bildpfad (damit die Anforderung einmal erfolgt, wodurch der Druck auf den Server verringert wird, allgemein bekannt als 占位图), nur wenn das Bild im sichtbaren Bereich des Browsers angezeigt wird. Der tatsächliche Pfad des Bildes wird festgelegt und der Server wird angefordert. .

Warum Lazy Loading verwenden?

懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求. Die Seitenladegeschwindigkeit ist schnell, was den Druck auf den Server verringern, Datenverkehr sparen und eine gute Benutzererfahrung bieten kann

Anwendungsbeispiel

Die Seite eines Einkaufszentrums hat beispielsweise eine große Anzahl von Bildern, und wenn sie auf einmal geladen wird, erscheint sie nicht länger als zehn Sekunden. Daher werden die von der Benutzeroberfläche benötigten Bilder zuerst angezeigt und müssen möglicherweise in Zukunft auf der Seite erscheinen und sie dann laden, wenn die Zukunft kommt (das Vorabladen wartet nicht auf die Zukunft und fordert direkt an).

Code zum Implementieren von verzögertem Laden von Bildern

Lazy Loading wird nicht verwendet动画.gif

使用懒加载,第一次进页面就快了不少 动画.gif

懒加载代码

原理:图片到最外层offsetTop距离-(图片最近滚动父元素)到最外层offsetTop距离-(图片最近滚动父元素)的scrollTop距离 <= (图片最近滚动父元素)clientHeight距离[+X] (当然可以为了更好的用户体验可以提前加载,再加上一个距离X)。(随便你怎么嵌套滚动,都是可以的,可以在这个基础上再判断父元素是否出现在body的可视范围内。)

看不懂描述没关系,看图

image.png

<template>
  <div>图片懒加载</div>
  <div class="imgFrame">
    <img
      v-for="(data, ind) in imgData"
      :key="ind"
      :src="imgSrcArray[ind]"
      :ref="imgDom"
    />
  </div>
</template>

<script lang="ts">
import { ref } from "vue";
export default {
  name: "App",
  setup() {
    let imgSrcArray = ref<string[]>([]);
    // 要懒加载的数据
    let imgData = ref<string[]>([
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/3.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/4.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/5.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/6.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/7.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/14.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/15.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/16.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/17.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/18.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/19.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/20.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/22.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/23.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/24.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/25.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/26.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/27.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/28.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/29.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/30.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/31.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/32.jpg",
      "https://cdn.jsdelivr.net/gh/lztnb/img@master/33.jpg",
    ]);
    // 使用默认图片
    imgData.value.forEach((val, ind: number) => {
      imgSrcArray.value[ind] =
        "https://acmphoto.oss-cn-beijing.aliyuncs.com/%E5%8A%A0%E8%BD%BD%E4%B8%AD4_3.png";
    });
    // imgDOM的元素
    let imgDomArray = ref<HTMLElement[]>([]);
    const imgDom = (el: HTMLElement) => {
      imgDomArray.value.push(el);
    };
    // 获取最近可以滚动的父元素
    function getParent<T extends HTMLElement>(e: T): T {
      let parentDom = e.parentNode;
      // eslint-disable-next-line no-constant-condition
      while (true) {
        if (parentDom == document.body) {
          break;
        }
        if ((parentDom as T).clientHeight == (parentDom as T).scrollHeight) {
          parentDom = getParent(parentDom as T);
        } else {
          break;
        }
      }
      return parentDom as T;
    }
    // 得到距离页面最上方的距离
    function getoffsetTop<T extends HTMLElement>(e: T): number {
      let offset = e.offsetTop;
      // 一直递归到最外层
      if (e.offsetParent != null) {
        offset += getoffsetTop(e.offsetParent as T);
      }
      return offset;
    }
    // 节流
    let time: number | null;
    onScroll();
    function onScroll() {
      if (time == null) {
        time = setTimeout(() => {
          onShow();
          time = null;
        }, 500);
      }
    }
    // 判断是否加载
    function onShow(): void {
      for (let i = 0; i < imgSrcArray.value.length; i++) {
        let cHeight = 0;
        let sTop = 0;
        let parentDom = getParent(imgDomArray.value[i]);
        parentDom.addEventListener("scroll", onScroll);
        if (parentDom == document.body) {
          cHeight = document.documentElement.clientHeight as number;
          sTop = document.documentElement.scrollTop as number;
          window.addEventListener("scroll", onScroll);
        } else {
          cHeight = parentDom.clientHeight;
          sTop = parentDom.scrollTop;
          parentDom.addEventListener("scroll", onScroll);
        }
        //判断是否加载的关键
        if (
          getoffsetTop(imgDomArray.value[i]) - getoffsetTop(parentDom) - sTop <=
          cHeight
        ) {
          imgSrcArray.value[i] = imgData.value[i];
        }
      }
    }
    return {
      imgData,
      imgSrcArray,
      imgDom,
    };
  },
};
</script>

<style scoped>
.imgFrame {
  margin-top: 20px;
  width: 800px;
  height: 600px;
  overflow: auto;
}
img {
  height: 100%;
  width: 100%;
  object-fit: contain;
}
</style>

复制代码

结语

通过这样的从理论到实操,应该对图片的预加载和懒加载都有所了解。不过在开发中还是有插件就用插件,这样使开发更快更简单,不用自己写很多代码,说不定还有bug。但是合格的打工人还是要知道原理和会手撸代码,插件可以用,当原理也要会。

Ich denke du magst

Origin juejin.im/post/7084190879140806669
Empfohlen
Rangfolge