← Back to list

Vue + JS 高效實現圖片懶加載

當網頁中的圖片加載過程中,特別是在網路不好的情況下,會變成網站的流量怪獸,讓網站變得很慢,甚至讓使用者直接放棄等待。最近我在工作中也碰到這個困擾,試過幾種解決方法,其中 Lazyload(懶加載)算是比較不錯的一個。不過,雖然 Vue…

Pass By Engineer · 2025-01-12 05:31 · 0 claps · 4.0 min read
#lazy-load #image #vue #intersection-observer
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Vue + JS 高效實現圖片懶加載

當網頁中的圖片加載過程中,特別是在網路不好的情況下,會變成網站的流量怪獸,讓網站變得很慢,甚至讓使用者直接放棄等待。最近我在工作中也碰到這個困擾,試過幾種解決方法,其中 Lazyload(懶加載)算是比較不錯的一個。不過,雖然 Vue 有很多懶加載套件,但總會遇到一些小問題,所以我決定自己寫一個來解決這個問題。

接下來我會簡單介紹一下怎麼手寫懶加載,還有 IntersectionObserver 的一些基本概念,讓你更容易理解和實現。

IntersectionObserver 介紹

簡單來說,IntersectionObserver就是觀察(observe)目標元素是否進入或離開可視區域(viewport)。

核心功能:

  1. 觀察目標元素可見性,追蹤元素是否進入或離開可見範圍
  2. 相比scroll,IntersectionObserver對效能影響較小
  3. 非同步回調: 當觀察條件達成後,觸發回調函數

常見用途:

  1. 延遲加載(Lazyload)
  2. 無限滾動(Infinite Scrolling)
  3. 觸發動畫

基本使用和參數介紹:

let option = {
  root: null,
  rootMargin: "0px",
  threshold: [0],
}
let observer = new IntersectionObserver(callback, options);

callback: 當目標元素與邊界交叉時觸發的函數。

options可選的配置物件:

  • root:用於測量可見性的容器,預設null表示使用瀏覽器的 viewport(視口)作為根元素
  • 可視範圍的邊距,類似 CSS 的 margin,例如 '0px 0px -50px 0px'(上,右,下,左)
  • threshold:用來指定目標元素在觀察範圍內的 可見比例

實現Lazyload

  1. 新增資料夾composable

  2. composable建立js文件useLazyPlugin,並新增自定義lazyload指令

const vLazy = {
  mounted(el, binding) {
    const optionLazyload = {
      root: null,
      rootMargin: "0px",
      threshold: [0],
    };

    const io = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        const lazyImage = entry.target;
        if (entry.intersectionRatio > 0) {
          lazyImage.src = binding.value;
          io.unobserve(lazyImage);
        }
      });
    }, optionLazyload);

    io.observe(el);
  },
};

export default vLazy;
  • io: 創建了一個新的 IntersectionObserver,接收一個回調函數和配置物件
  • entries: 觀察器每次觸發時,會傳入一組 entries,其中每個 entry 代表一個被觀察的目標元素
  • intersectionRatio: intersectionRatioIntersectionObserverEntry 提供的一個屬性,它表示目標元素與根元素(或視口)之間的可見比例,取值範圍是 0 到 1
  • unobserve: 用來 停止觀察目標元素 的方法,調用 unobserve 可以釋放資源,避免不必要的性能消耗
  1. App.vue,使用自定義指令
<template>
  <div class="list">
    <img
      v-for="item in 20"
      :key="item"
      v-lazy="`https://fakeimg.pl/${item * 100}`"
      alt=""
    />
  </div>
</template>

<script setup>
import vLazy from "./composable/lazyload/useLazyPlugin";
</script>

以上就是簡單的Lazyload實作,可以透過許多方式來擴展這個功能,例如新增動畫效果或是實現其他功能,各位有空不妨自己玩看看吧

圖片來源: https://www.smashingmagazine.com/2021/07/dynamic-header-intersection-observer/


메타데이터
post_id
2f1f2f5ab3f0
slug
vue-js-高效實現圖片懶加載-2f1f2f5ab3f0
url
https://medium.com/@gww680923/vue-js-%E9%AB%98%E6%95%88%E5%AF%A6%E7%8F%BE%E5%9C%96%E7%89%87%E6%87%B6%E5%8A%A0%E8%BC%89-2f1f2f5ab3f0
canonical_url
https://medium.com/@gww680923/vue-js-%E9%AB%98%E6%95%88%E5%AF%A6%E7%8F%BE%E5%9C%96%E7%89%87%E6%87%B6%E5%8A%A0%E8%BC%89-2f1f2f5ab3f0
author_url
https://medium.com/@gww680923
status
ok
fetched_at
2026-06-09 15:37:30