Vue回爐重造之圖片加載性能優化

前言

圖片加載優化對於一個網站性能好壞起着至關重要的作用。所以我們使用Vue來操作一波。

備註

以下的優化一、優化二欄目都是我自己封裝在Vue的工具函數裏,所以請認真看完,要不然直接複製的話,容易出錯的。

資源

  • Vue.js
  • Element UI

優化一:圖片加載動畫

只有當圖片加載完成後纔可以顯示圖片,加載動畫結束。我們使用Element UI中的loading組件來用作加載的動畫。假設一個變量loading初始值爲true,當圖片加載完時爲false

    // 圖片加載
    imgLoad:(src)=>{
      let bgImg = new Image();
      bgImg.src = src; // 獲取背景圖片的url
      bgImg.onerror = () => {
        console.log("img onerror");
      };
      bgImg.onload = () => {
        // 等背景圖片加載成功後 去除loading
        console.log("加載完成");
        return false
      };
    }, 

優化二:圖片懶加載

當圖片處於視口位置時,纔會請求圖片。這個優化不僅可以用在網站首頁,還可以用在圖片比較多的網頁,節約性能。話不多說,我們來實現一波。

    // 獲取圖片距離   
    getRect(element) {
      const rect = element.getBoundingClientRect();
      const top = !document.documentElement.clientTop ? document.documentElement.clientTop : 0;
      const left = !document.documentElement.clientLeft ? document.documentElement.clientLeft : 0;
      return {
          top: rect.top - top,
          bottom: rect.bottom - top,
          left: rect.left - left,
          right: rect.right - left
      }
    },
    // 封裝圖片懶加載
    lazyload() {
      let img = document.getElementsByTagName("img");
      let len = img.length;
      let n = 0; // 存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷
      // 可見區域高度
      const seeHeight = window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight; 
      for (let i = n; i < len; i++) {
          // 如果圖片距頂部距離小於可見區域高度與滾動條距離頂部高度之和時,才顯示圖片
          let rectTop = this.getRect(img[i]).top;      // 這裏的this.getRect()是用來獲取圖片位置的。
          let rectBottom= this.getRect(img[i]).bottom; 
          if (rectTop > 0 && rectTop < seeHeight && rectBottom > 0 && rectBottom < seeHeight) { // 已經在視口
              img[i].getAttribute("src") === ""?(img[i].setAttribute('class', 'opacity'),img[i].src = img[i].getAttribute("data-src")):n = i + 1;
          } else if(rectTop < seeHeight && rectBottom >= seeHeight){ // 正在進入視口
              img[i].getAttribute("src") === ""?(img[i].setAttribute('class', 'opacity'),img[i].src = img[i].getAttribute("data-src")):n = i + 1;
          }
      }
    }

這裏的設置類名opacity可以自己根據喜歡的動畫設置。我這裏寫的是這樣的,可以參考一下。

.opacity {
  animation: 0.3s ani linear;
}
@keyframes ani {
  0% {
    opacity: 0;
    transform: translateX(-200px);
  }
  100% {
    opacity: 1;
    transform: translateX(0px);
  }
}

整合工具包

我們做Vue腳手架項目時,經常會用到很多重複的代碼段或者方法函數,所以我們可以封裝起來,想用的時候就用,也避免了代碼冗餘。
1、在src根目錄下創建util文件夾,裏面創建util.js;
2、在src根目錄下的main.js中鍵入以下代碼,引入util.js,並且全局註冊;

import utils from './util/util'

Vue.prototype.$utils=utils

3、編輯util.js;

export default {
    // 圖片加載
    imgLoad:(src)=>{
      let bgImg = new Image();
      bgImg.src = src; // 獲取背景圖片的url
      bgImg.onerror = () => {
        console.log("img onerror");
      };
      bgImg.onload = () => {
        // 等背景圖片加載成功後 去除loading
        console.log("加載完成");
        return false
      };
    }, 
    // 獲取元素距離   
    getRect(element) {
      const rect = element.getBoundingClientRect();
      const top = !document.documentElement.clientTop ? document.documentElement.clientTop : 0;
      const left = !document.documentElement.clientLeft ? document.documentElement.clientLeft : 0;
      return {
          top: rect.top - top,
          bottom: rect.bottom - top,
          left: rect.left - left,
          right: rect.right - left
      }
    },
    // 封裝圖片懶加載
    lazyload() {
      let img = document.getElementsByTagName("img");
      let len = img.length;
      let n = 0; // 存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷
      // 可見區域高度
      const seeHeight = window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight; 
      for (let i = n; i < len; i++) {
          // 如果圖片距頂部距離小於可見區域高度與滾動條距離頂部高度之和時,才顯示圖片
          let rectTop = this.getRect(img[i]).top;
          let rectBottom= this.getRect(img[i]).bottom;
          if (rectTop > 0 && rectTop < seeHeight && rectBottom > 0 && rectBottom < seeHeight) {
              img[i].getAttribute("src") === ""?(img[i].setAttribute('class', 'opacity'),img[i].src = img[i].getAttribute("data-src")):n = i + 1;
          } else if(rectTop < seeHeight && rectBottom >= seeHeight){
              img[i].getAttribute("src") === ""?(img[i].setAttribute('class', 'opacity'),img[i].src = img[i].getAttribute("data-src")):n = i + 1;
          }
      }
    }
}

實例

我們封裝了工具函數,那麼我們就使用它,這裏使用this.$utils調用每個方法。

應用:圖片加載動畫

我們在一個頁面這樣使用了它,this.bannerSrc是圖片地址,this.loading是加載動畫的狀態。

  mounted() {
    if (!this.$utils.imgLoad(this.bannerSrc)) {
      this.loading = false;
    }
  }

應用:圖片懶加載

1、設置keep-alive的頁面

  methods: {
    // 懶加載圖片
    scrollView() {
      const fn = this.$utils.lazyload.bind(this.$utils);
      window.addEventListener("scroll", fn);
      // 離開組件
      this.$once("hook:deactivated", function() {
        window.removeEventListener("scroll", fn);
      });
    }
  },
  activated() {
    this.scrollView();
  },
  mounted() {
     this.$utils.lazyload(); // 初始化
  }

2、未設置keep-alive的頁面

  mounted() {
    this.$utils.lazyload();
    window.addEventListener("scroll", this.$utils.lazyload.bind(this.$utils));
  },
  beforeDestroy(){
    window.removeEventListener("scroll", this.$utils.lazyload.bind(this.$utils));
  }

作者:Vam的金豆之路
主要領域:前端開發
我的微信:maomin9761
微信公衆號:前端歷劫之路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章