<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Vuejs】1811- Vue3如何優(yōu)雅的加載圖片

          共 6840字,需瀏覽 14分鐘

           ·

          2023-09-25 16:13

          最近開發(fā)了一個功能,頁面首頁會加載大量的圖片,初次進入頁面時,會導致頁面性能下降,

          于是乎,我改進了這個功能,可以讓所有圖片自動懶加載。

          ?? 原理

          這個功能主要的底層邏輯是是使用IntersectionObserver APIIntersectionObserver用于在瀏覽器中觀察元素的可見性和位置變化。它可以幫助開發(fā)者實現(xiàn)一些動態(tài)行為,如圖片的懶加載、無限滾動等。

          簡單的示例如下:

          // 創(chuàng)建IntersectionObserver實例
          const observer = new IntersectionObserver((entries, observer) => {
            // 遍歷觀察的元素
            entries.forEach(entry => {
              // 如果元素可見
              if (entry.isIntersecting) {
                // 加載圖片
                const img = entry.target;
                const src = img.getAttribute('src');
                img.setAttribute('src', src);
                // 停止觀察該元素
                observer.unobserve(img);
              }
            });
          });

          // 獲取所有需要懶加載的圖片元素
          const lazyImages = document.querySelectorAll('.lazy-image');

          // 觀察每個圖片元素
          lazyImages.forEach(image => {
            observer.observe(image);
          });

          ?? 實踐

          接下來我們實現(xiàn)一個通用的 hook,基本的功能如下:

          1. 給圖片提供默認的占位圖片 src,同時提供src屬性
          2. 傳入圖片對應的 ref 屬性。
          3. 當圖片進入可視區(qū)域時,使用src屬性替換 src 屬性
          import { onMounted, Ref } from "vue";
          const options = {
            // root: document.querySelector(".container"), // 根元素,默認為視口
            rootMargin: "0px"// 根元素的邊距
            threshold: 0.5// 可見性比例閾值
            once: true,
          };

          function callback(
            entries: IntersectionObserverEntry[],
            observer: IntersectionObserver
          {
            entries.forEach((entry) => {
              // 處理每個目標元素的可見性變化
              if (entry.intersectionRatio <= 0return;
              const img: Element = entry.target;
              const src = img.getAttribute("src");

              img.setAttribute("src", src ?? ""); // 將真實的圖片地址賦給 src 屬性

              observer.unobserve(img);
            });
          }

          export const useInView = (ref: Ref) => {
            const observer = new IntersectionObserver(callback, options);

            onMounted(() => {
              Object.keys(ref.value).forEach((e) => observer.observe(ref.value[e]));
            });
          };

          <script setup lang="ts">
          import { ref } from "vue";
          import { useInView } from "./hooks/useInView";

          const imgRef = ref(null);
          useInView(imgRef);
          </script>

          <template>
            <h4>公眾號:萌萌噠草頭將軍</h4>
            <div
              v-for="(_, idx) in new Array(200).fill(11)"
            >

              <img
                ref="imgRef"
                src="https://via.placeholder.com/200"
                :src="`https://picsum.photos/200/${180 + idx}`"
                alt="b"
              />

            </div>
          </template>

          實際效果如下

          雖然基本的功能要求已經(jīng)完成了,但是現(xiàn)在還不夠優(yōu)雅!?。?/p>

          ?? 優(yōu)化

          接下來,我們增加個過渡動畫。每次當加載完圖片,就從占位圖過渡到正常圖片模式。

          img.onload = () => {
            img.setAttribute('class''fade-in')
          }
          @keyframes fadeIn {
            from {
              opacity0;
            }
            to {
              opacity1;
            }
          }

          /* 應用淡入動畫到元素 */
          .fade-in {
            animation: fadeIn 0.6s ease-in;
          }

          完整代碼如下:

          import { onMounted, Ref } from "vue";
          const options = {
            // root: document.querySelector(".container"), // 根元素,默認為視口
            rootMargin: "0px"// 根元素的邊距
            threshold: 0.5// 可見性比例閾值
            once: true,
          };

          function callback(
            entries: IntersectionObserverEntry[],
            observer: IntersectionObserver
          {
            entries.forEach((entry) => {
              if (entry.intersectionRatio <= 0return;
              const img = entry.target as HTMLImageElement;
              const src = img.getAttribute("src");

              img.setAttribute("src", src ?? ""); // 將真實的圖片地址賦給 src 屬性

              img.onload = () => {
                img.setAttribute("class""fade-in");
              };

              observer.unobserve(img);
            });
          }

          export const useInView = (ref: Ref) => {
            const observer = new IntersectionObserver(
              callback,
              options
            );

            onMounted(() => {
              Object.keys(ref.value)
                .forEach((e) => observer.observe(ref.value[e]));
            });
          };
          <script setup lang="ts">
          import { ref } from "vue";
          import { useInView } from "./hooks/useInView";

          const imgRef = ref(null);

          useInView(imgRef);

          </script>

          <template>
            <h4>公眾號:萌萌噠草頭將軍</h4>
            <div
              v-for="(_, idx) in new Array(200).fill(11)"
              style="width: 200px height: 200px;"
            >

              <img
                ref="imgRef"
                style="height: 100%"
                src="https://via.placeholder.com/200"
                :src="`https://picsum.photos/200/${180 + idx}`"
                alt="b"
              />

            </div>
          </template>

          <style scoped>
          /* 定義淡入動畫 */
          @keyframes fadeIn {
            from {
              opacity0;
            }
            to {
              opacity1;
            }
          }

          /* 應用淡入動畫到元素 */
          .fade-in {
            animation: fadeIn 0.6s ease-in;
          }
          </style>

          瀏覽 433
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲yw无码在线免费观看 | jiZZJIZZ日本丰满熟妇 | 三级片在线观看中文字幕 | 国产无码精彩视频 | 摸逼网|