Vue 自定義圖片懶加載指令v-lazyload


  Vue是可以自定義指令的,最近學習過程中遇見了一個需要圖片懶加載的功能,最后參考了別人的代碼和思路自己重新寫了一遍。以下將詳細介紹如何實現自定義指令v-lazyload。

  先看如何使用這個指令:

  

<img v-lazyload="imageSrc" >

  imageSrc是要加載的圖片的實際路徑。

  為了實現這個指令,我們首先單獨建立一個文件,名字為lazyload.js.並填寫基本的代碼,如下:

  

//Vue 圖片懶加載,導出模塊
export default (Vue , options = {})=>{
  //初始化的選項,default是未加載圖片時顯示的默認圖片
var init = {    default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png' }
  //addListener為Vue指令的具體實現功能函數,我們這里為所有使用v-lazyload的指令的元素添加監聽
  //ele 是dom元素,binding是綁定的具體值,
  //例如:<img v-lazyload="imageSrc" > ele是img binding是imageSrc
  const addListenner = (ele,binding) =>{
    
  }
  //Vue自定義指令,lazyload為指令的名稱 Vue.directive('lazyload',{ inserted:addListener, updated:addListener }) }

inserted 和 updated為Vue指令的執行不同階段提供的鈎子函數,查看Vue的官網可以看到一共有5個階段,

 

指令定義函數提供了幾個鈎子函數(可選):

  • bind: 只調用一次,指令第一次綁定到元素時調用,用這個鈎子函數可以定義一個在綁定時執行一次的初始化動作。

  • inserted: 被綁定元素插入父節點時調用(父節點存在即可調用,不必存在於 document 中)。

  • update: 被綁定元素所在的模板更新時調用,而不論綁定值是否變化。通過比較更新前后的綁定值,可以忽略不必要的模板更新(詳細的鈎子函數參數見下)。

  • componentUpdated: 被綁定元素所在模板完成一次更新周期時調用。

  • unbind: 只調用一次, 指令與元素解綁時調用。

這里我們只用inserted和updated就夠了。

  接下來我們具體實現addListener的實現。我們的具體思路如下:

  1、先看看這個圖片是否需要懶加載。有兩種情況是不需要加載的,一是圖片還沒到達可視區域,二是圖片已經加載過了。

  2、然后監聽窗口的scroll事件,判斷哪些圖片可以進行加載了。

  這里我們需要一個需要進行監聽需要懶加載的圖片列表和一個需要記錄已經加載過得圖片列表。另外為了方便數組的操作,我們加一個數組的remove方法。

  繼續我們的代碼。

//Vue 圖片懶加載
export default (Vue , options = {})=>{
  
  //數組item remove方法
  if(!Array.prototype.remove){
        Array.prototype.remove = function(item){ if(!this.length) return var index = this.indexOf(item); if( index > -1){ this.splice(index,1); return this } } }
  var init = {   
    default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png'
  }  
  //需要進行監聽的圖片列表,還沒有加載過得
  
var listenList = [];
  //已經加載過得圖片緩存列表
var imageCatcheList = [];   //是否已經加載過了 const isAlredyLoad = (imageSrc) => { } //檢測圖片是否可以加載,如果可以則進行加載 const isCanShow = (item) =>{ };   //添加監聽事件scroll const onListenScroll = () =>{ } //Vue 指令最終的方法 const addListener = (ele,binding) =>{ //綁定的圖片地址 var imageSrc = binding.value; //如果已經加載過,則無需重新加載,直接將src賦值 if(isAlredyLoad(imageSrc)){ ele.src = imageSrc; return false; } var item = { ele:ele, src:imageSrc } //圖片顯示默認的圖片 ele.src = init.default; //再看看是否可以顯示此圖片 if(isCanShow(item)){ return } //否則將圖片地址和元素均放入監聽的lisenList里 listenList.push(item); //然后開始監聽頁面scroll事件 onListenScroll(); } Vue.directive('lazyload',{ inserted:addListener, updated:addListener }) }

接下來就幾個空方法的實現了。

isAlredyLoad ,判斷是否已經加載過了這個圖片
const isAlredyLoad = (imageSrc) => {
        if(imageCatcheList.indexOf(imageSrc) > -1){
            return true;
        }else{
            return false;
        }
    }

isCanShow 圖片是否進入可視區域,如果已經進入則進行加載

//檢測圖片是否可以加載,如果可以則進行加載
    const isCanShow = (item) =>{
        var ele = item.ele;
        var src = item.src;
        //圖片距離頁面頂部的距離
        var top = ele.getBoundingClientRect().top;
        //頁面可視區域的高度
        var windowHeight = window.innerHight;
        //top + 10 已經進入了可視區域10像素
        if(top + 10 < window.innerHeight){
            var image = new Image();
            image.src = src;
            image.onload = function(){
                ele.src = src;
                imageCatcheList.push(src);
                listenList.remove(item);
            }
            return true;
        }else{
            return false;
        }
    };

 

onListenScroll監聽滾動事件,並且檢測是否進入可視區域。
const onListenScroll = () =>{
        window.addEventListener('scroll',function(){
            var length = listenList.length;
            for(let i = 0;i<length;i++ ){
                isCanShow(listenList[i]);
            }
        })
    }

最終我們的代碼如下:

//Vue 圖片懶加載
export default (Vue , options = {})=>{
    if(!Array.prototype.remove){
        Array.prototype.remove = function(item){
            if(!this.length) return
            var index = this.indexOf(item);
            if( index > -1){
                this.splice(index,1);
                return this
            }
        }
    }
    var init = {
        lazyLoad: false,
      default: 'https://gw.alicdn.com/tps/i1/TB147JCLFXXXXc1XVXXxGsw1VXX-112-168.png'
    }

    var listenList = [];
    var imageCatcheList = [];

    const isAlredyLoad = (imageSrc) => {
        if(imageCatcheList.indexOf(imageSrc) > -1){
            return true;
        }else{
            return false;
        }
    }
    //檢測圖片是否可以加載,如果可以則進行加載
    const isCanShow = (item) =>{
        var ele = item.ele;
        var src = item.src;
        //圖片距離頁面頂部的距離
        var top = ele.getBoundingClientRect().top;
        //頁面可視區域的高度
        var windowHeight = window.innerHight;
        //top + 10 已經進入了可視區域10像素
        if(top + 10 < window.innerHeight){
            var image = new Image();
            image.src = src;
            image.onload = function(){
                ele.src = src;
                imageCatcheList.push(src);
                listenList.remove(item);
            }
            return true;
        }else{
            return false;
        }
    };

    const onListenScroll = () =>{
        window.addEventListener('scroll',function(){
            var length = listenList.length;
            for(let i = 0;i<length;i++ ){
                isCanShow(listenList[i]);
            }
        })
    }
    //Vue 指令最終的方法
    const addListener = (ele,binding) =>{
        //綁定的圖片地址
        var imageSrc = binding.value;
        //如果已經加載過,則無需重新加載,直接將src賦值
        if(isAlredyLoad(imageSrc)){
            ele.src = imageSrc;
            return false;
        }
        var item = {
            ele:ele,
            src:imageSrc
        }
        //圖片顯示默認的圖片
        ele.src = init.default;
        //再看看是否可以顯示此圖片
        if(isCanShow(item)){
            return
        }
        //否則將圖片地址和元素均放入監聽的lisenList里
        listenList.push(item);
        
        //然后開始監聽頁面scroll事件
        onListenScroll();
    }

    Vue.directive('lazyload',{
        inserted:addListener,
        updated:addListener
    })
}

使用時需要在主文件中引入這個文件,並且vue.use();

import LazyLoad from 'lazyLoad.js'
Vue.use(LazyLoad);

並且在需要懶加載的圖片上均按照如下使用v-lazyload指令即可

<img v-lazyload="imageSrc" >


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM