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


Posted in Javascript onDecember 31, 2020

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript DOM 学习第七章 表单的扩展
Feb 19 Javascript
javascript创建数组之联合数组的使用方法示例
Dec 26 Javascript
JavaScript实现自动弹出窗口并自动关闭窗口的方法
Aug 06 Javascript
一种新的javascript对象创建方式Object.create()
Dec 28 Javascript
Web开发必知Javascript技巧大全
Feb 23 Javascript
js控制按钮,防止频繁点击响应的实例
Feb 15 Javascript
Bootstrap fileinput文件上传组件使用详解
Jun 06 Javascript
一个简易的js图片轮播效果
Jul 22 Javascript
详解vue-cli 脚手架 安装
Apr 16 Javascript
ES6小技巧之代替lodash
Jun 07 Javascript
vue + typescript + video.js实现 流媒体播放 视频监控功能
Jul 07 Javascript
移动端吸顶fixbar的解决方案详解
Jul 17 Javascript
JavaScript实现反转字符串的方法详解
Apr 27 #Javascript
jquery 禁止鼠标右键并监听右键事件
Apr 27 #jQuery
jQuery EasyUI tree增加搜索功能的实现方法
Apr 27 #jQuery
js实现添加删除表格(两种方法)
Apr 27 #Javascript
JS/jquery实现一个网页内同时调用多个倒计时的方法
Apr 27 #jQuery
vue2 前后端分离项目ajax跨域session问题解决方法
Apr 27 #Javascript
Webpack中css-loader和less-loader的使用教程
Apr 27 #Javascript
You might like
色色整理的PHP面试题集锦
2012/03/08 PHP
PHP改进计算字符串相似度的函数similar_text()、levenshtein()
2014/10/27 PHP
php强大的时间转换函数strtotime
2016/02/18 PHP
PHP时间戳格式全部汇总 (获取时间、时间戳)
2016/06/13 PHP
详谈PHP中的密码安全性Password Hashing
2017/02/04 PHP
getElementById在任意一款浏览器中都可以用吗的疑问回复
2007/05/13 Javascript
JavaScript 定义function的三种方式小结
2009/10/16 Javascript
js动态给table添加/删除tr的方法
2013/08/02 Javascript
JavaScript简单实现鼠标拖动选择功能
2014/03/06 Javascript
JS判断是否在微信浏览器打开的简单实例(推荐)
2016/08/24 Javascript
vue集成kindeditor富文本的实现示例代码
2019/06/07 Javascript
Vue全局loading及错误提示的思路与实现
2019/08/09 Javascript
webpack的pitching loader详解
2019/09/23 Javascript
vue 强制组件重新渲染(重置)的两种方案
2019/10/29 Javascript
vue实现鼠标移过出现下拉二级菜单功能
2019/12/12 Javascript
javascript 原型与原型链的理解及应用实例分析
2020/02/10 Javascript
JS实现碰撞检测效果
2020/03/12 Javascript
JS如何实现封装列表右滑动删除收藏按钮
2020/07/23 Javascript
[05:09]2016国际邀请赛中国区预选赛淘汰赛首日精彩回顾
2016/06/29 DOTA
在Python的Flask框架中实现全文搜索功能
2015/04/20 Python
基于python的七种经典排序算法(推荐)
2016/12/08 Python
python实现redis三种cas事务操作
2017/12/19 Python
flask中的wtforms使用方法
2018/07/21 Python
详解python校验SQL脚本命名规则
2019/03/22 Python
Python实现爬取亚马逊数据并打印出Excel文件操作示例
2019/05/16 Python
10个python3常用排序算法详细说明与实例(快速排序,冒泡排序,桶排序,基数排序,堆排序,希尔排序,归并排序,计数排序)
2020/03/17 Python
python logging.info在终端没输出的解决
2020/05/12 Python
OpenCV+python实现实时目标检测功能
2020/06/24 Python
Python selenium键盘鼠标事件实现过程详解
2020/07/28 Python
如何基于Python实现word文档重新排版
2020/09/29 Python
如何在pycharm中安装第三方包
2020/10/27 Python
python语言time库和datetime库基本使用详解
2020/12/25 Python
2014党员民主评议个人思想剖析发言
2014/09/19 职场文书
会计专业2019暑假实习报告
2019/06/21 职场文书
基于Redis延迟队列的实现代码
2021/05/13 Redis
解决MySQL Varchar 类型尾部空格的问题
2022/04/06 MySQL