Vue自定义指令v-lazyload实现图片懒加载详解

作者:青团子时间:2026-10-22 03:35:21浏览:645

本文详细介绍如何在Vue中通过自定义指令实现图片懒加载功能。通过定义v-lazyload指令,利用inserted和updated钩子函数监听滚动事件,判断图片是否进入可视区域后再进行加载,从而提升页面性能。

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" >

以上为本文全部内容,希望对各位的学习有所帮助,也欢迎大家继续支持本站。

作者最新文章