[jQuery插件]手写一个图片懒加载实现
教你做图片懒加载插件
那一年
那一年,我还年轻 刚接手一个ASP.NET MVC 的 web 项目,
(C#/jQuery/Bootstrap)
并没有做 web 的经验,没有预留学习时间,
(作为项目组长的我,主要C#客户端经验)
项目来了只能硬上,把JS比作C#来写(哭
当时接到请求协助解决一个图片显示慢的问题时,给出了一个后来看来不好的解决方案。
那个项目结束一段时间之后,内心愧疚的我把这个图片懒加载的jQuery插件发了过去。(现在我JS已经搞很溜了你信不信,哇哈哈~)
jQuery 的辉煌时代已成过去,
但不能否定这是个非常优秀的 js 库,
而且仍有大量旧网站在用它。
今天聊一下如何开发一个基于 jQuery 的图片懒加载插件(当然只要你想也可以脱离jQuery用纯原生js)。
工作原理
如何才能懒加载呢?
- 页面初始加载时统一设置一个fake图片
- 在data属性上记录真实图片的url地址
- 在预期的时机请求相应的图片资源
以上,就是一个图片懒加载插件的大致工作原理。
准备
滚动加载
假设一个这样的场景:
- 页面有大量图片
- 出现有滚动条
- 可视范围内的图片要加载
- 可视范围外的图片仍为占位图
- 当滚动时,可视范围外的图片进入(或即将进入)可视范围则发起请求获取图片并显示
带滚动条的图片展示页面
先创建一个demo-lazyload-window-scroll.html
的图片展示页面,效果如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>demo-lazyload</title>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.min.js"></script>
<style>
.container{
padding:10px 50px;
display: flex;
flex-direction: column;
align-items: center;
height: 300px;
overflow-y: auto;
border: 1px solid gray;
background-color: lightskyblue;
}
.img{
flex: 1;
margin: 10px 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<h2>用于展示图片的页面,检验我们的懒加载插件</h2>
<div id="container" class="container">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1575255351&di=f793ab57355f48f8dac4dd9c84df3f79&imgtype=jpg&er=1&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fa%2F591580f307d75.jpg">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="http://pic41.nipic.com/20140514/13102479_214919550103_2.jpg">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="http://pic41.nipic.com/20140514/13102479_215137440121_2.jpg">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="http://pic38.nipic.com/20140213/9422601_094926378000_2.jpg">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="http://pic41.nipic.com/20140505/9448607_213048662000_2.jpg">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="https://setouchifinder.com/ja/wp-content/uploads/sites/2/2018/03/01onokorojima.jpg">
<img src="./blank_img.png" alt="" class="img" data-lazysrc="http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1703/23/c15/40225820_1490275789503.jpg">
</div>
</body>
</html>
- 通过CDN引入了jQuery
container
里有7张图片,src都是一个占位用空图片data-lazysrc
的值才是真正要显示的图片,我们插件里就取这个值来用
预想的用法
在上面的html
页面,
- 引入我们将要完成的插件js
- 调用混入进jQuery的
lazyLoad
方法
就是这么简单
<script src="./jquery.lazyloader.js"></script>
<script>
window.onload = function() {
$('.img').lazyLoad()
}
</script>
IIFE
在没有js模块化的年代,人们通过IIFE
来解决作用域问题。
IIFE
全称Immediately Invoked Function Expression
,
即立即执行函数表达式,通过用一个立即执行的函数的形式,
包裹起这个函数的作用域。
(function() {
// coding here
root.xx = function(){}
})(root)
然后通过参数传入全局对象等参数,
将插件对象挂载到全局对象上,
以实现在页面上直接使用。
那时的jQuery等库也都是这种风格形式的,插件也不例外。
开发jQuery的插件,要用到jQuery的extend
方法,传入一个对象,就可以将对象的属性方法给扩展到现有jQuery对象上。
(function() {
// coding here
$.fn.extend({
lazyLoad: function() {}
})
})()
剩下的就是去实现我们的lazyLoad
方法了
具体实现
lazyLoad
创建js文件:jquery.lazyloader.js
这时我们要考虑如下几点:
- 页面加载时要显示可视区域的图片
- 其它等滚动时再获取并显示(如果有的话)
这样,任务可以分解为:
- 工具函数:判断是否进入可视区域
- 公用函数:获取未显示img元素的真实图片地址,并显示(设到src属性)
- 监听滚动:调用显示图片的函数逻辑即可
同时还要注意对已通过懒加载显示完的图片不在进行处理
(function() {
// coding here
$.fn.extend({
lazyLoad: function() {
var that = this
// 初始化时加载一次进入可视区域的图片
showRealImage(this)
// 滚动条拖动时显示未加载且进入(即将进入)可视区域的图片
$(window).scroll(function(){
showRealImage(that)
})
}
})
/**
* 修改进入可视区域的图像元素的真实图像地址使之显示
*
* @param {*} $eleList
*/
function showRealImage($eleList){
if(!$eleList || !$eleList.length){
return
}
// 先过滤,后处理
$eleList.filter((i, ele)=>{
var $img = $(ele)
// 作为处理对象的条件:
// 1.未加载
// 2.进入可视区域
// 3.DOM标签为img
return !$img.attr('loaded') && isInSight($img) && ele.nodeName.toLowerCase() === 'img'
}).each(function(i,ele){
var $img = $(ele)
var source = $img.data('lazysrc')
if(source){
// 显示真实图片
$img.attr('src', source)
}
// 设为已加载,之后不再需要处理
$img.attr('loaded', true)
})
/**
*判断图像元素是否进入可视区域(包含预加载Offset的距离)
*
* @param {*} $node
*/
function isInSight($node){
return ($node.offset().top - 50) <= $(window).height()+$(window).scrollTop();
}
}
})()
现在就可以打开demo-lazyload-window-scroll.html
试一下效果了。
为了效果明显,可以将网络调为3G。
验证方法
F12打开页面调试工具,通过watch查看图片的src,可以看到初始状态下只有第一张是显示了真是图片的;
一边拖动滚动条,一边刷新watch的结果,可以看到在距离马上就要显示下一张的时候,就会加载出它的真实图片。
存在的问题
虽然能够看到效果了,但是:
- 这里我们用了固定的offset值
- 还用了默认的图片父元素/容器:window
实际上的情况肯定要复杂,这样可不是个合格的插件。
比如当显示图片的区域只是一部分而不是整个window的时候,这里就会失效了。
改进
针对上面提到的情况,我们创建另外一个html文件:
demo-lazyload-container-scroll.html
在这个html文件里,图片显示区域作为子元素被一个div
包裹。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>demo-lazyload</title>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.min.js"></script>
<style>
.container{
padding:10px 50px;
display: flex;
flex-direction: column;
align-items: center;
height: 300px;
overflow-y: auto;
border: 1px solid gray;
background-color: lightskyblue;
}
.img{
flex: 1;
margin: 10px 0;
width: 100%;
}
</style>
</head>
<body>
<h2>用于展示图片的页面,检验我们的懒加载插件(非window滚动)</h2>
<div id="container" class="container">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1575255351&di=f793ab57355f48f8dac4dd9c84df3f79&imgtype=jpg&er=1&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fa%2F591580f307d75.jpg">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="http://pic41.nipic.com/20140514/13102479_214919550103_2.jpg">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="http://pic41.nipic.com/20140514/13102479_215137440121_2.jpg">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="http://pic38.nipic.com/20140213/9422601_094926378000_2.jpg">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="http://pic41.nipic.com/20140505/9448607_213048662000_2.jpg">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="https://setouchifinder.com/ja/wp-content/uploads/sites/2/2018/03/01onokorojima.jpg">
<img src="https://s2.ax1x.com/2019/11/25/MXLO6f.png" alt="" class="img" data-lazysrc="http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1703/23/c15/40225820_1490275789503.jpg">
</div>
<script src="./jquery.lazyloader.js"></script>
<script>
window.onload = function() {
$('.img').lazyLoad({
preOffset: 80,
container: document.getElementById('container')
})
}
</script>
</body>
</html>
页面效果图:
- 上面将占位图片由本地文件换为了线上图片,对于验证没有影响。
- 这次在调用懒加载方法时,传入了自定义内容作参数:
- 预加载Offset的距离:offset
当拖动滚动条,下一张图片距离要显示还有这些像素的时候开始加载 - container元素:container
图片区域的父元素,滚动对象
- 预加载Offset的距离:offset
页面中script调用处:
<script>
window.onload = function() {
$('.img').lazyLoad({
preOffset: 80,
container: document.getElementById('container')
})
}
</script>
详情参照注释文字,完整的实现如下:
/**
* 图片懒加载jQuery插件
*
* 2019-07-25
* CoderMonkie
*/
(function(){
// 配置信息
var options = {}
/**
* 默认配置
*/
function defaultOptions(){
return {
preOffset: 100,
container: window
}
}
// 扩展 lazyLoad 方法
$.fn.extend({
lazyLoad: function(setting){
var that = this
options = defaultOptions()
// 确保参数合法的情况下
if(setting && toString.call(setting) === '[object Object]') {
// 确保参数里设定项目的值的类型正确
// preOffset:数值(负数没有意义,NaN更不符合要求: >= 0)
// container:DOM元素
if(setting.preOffset && typeof(setting.preOffset) === 'number' && setting.preOffset >= 0){
options.preOffset = setting.preOffset;
}
if(setting.container && setting.container.nodeType){
options.container = setting.container
}
}
// 初始化时加载一次进入可视区域的图片
showRealImage(this)
// 滚动条拖动时显示未加载且进入(即将进入)可视区域的图片
$(options.container).scroll(()=>{
showRealImage(that)
})
}
})
/**
*修改进入可视区域的图像元素的真实图像地址使之显示
*
* @param {*} $eleList
*/
function showRealImage($eleList){
if(!$eleList || !$eleList.length){
return
}
// 先过滤,后处理
$eleList.filter((i, ele)=>{
var $img = $(ele)
// 作为处理对象的条件:
// 1.未加载
// 2.进入可视区域
// 3.DOM标签为img
return !$img.attr('loaded') && isInSight($img) && ele.nodeName.toLowerCase() === 'img'
}).each(function(i,ele){
var $img = $(ele)
var source = $img.data('lazysrc')
if(source){
// 显示真实图片
$img.attr('src', source)
}
// 设为已加载,之后不再需要处理
$img.attr('loaded', true)
})
/**
*判断图像元素是否进入可视区域(包含预加载Offset的距离)
*
* @param {*} $node
*/
function isInSight($node){
return ($node.offset().top - options.preOffset) <= $(options.container).height() + $(options.container).scrollTop();
}
}
})()
[jQuery插件]手写一个图片懒加载实现的更多相关文章
- Vue实现一个图片懒加载插件(转载)
Vue是可以自定义指令的,最近学习过程中遇见了一个需要图片懒加载的功能,最后参考了别人的代码和思路自己重新写了一遍.以下将详细介绍如何实现自定义指令v-lazyload. 先看如何使用这个指令: &l ...
- 闭包,jQuery插件的写法:图片预加载
最近做的一些网页,单个网页图片量都比较大,网络不好的情况下,特别卡,这个图片预加载的方法可以牺牲一些时间换来网页的浏览顺畅,还是值得的. //闭包的写法,它内部的变量都是局部的,不会和外部巳有的变量进 ...
- 用jquery写的图片懒加载
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- 插件:★★★ !!!图片懒加载 lazyload.js 、 jquery.scrollLoading.js
插件:图片懒加载 jquery.lazyload.js 2016-3-31 插件说明:http://www.w3cways.com/1765.html (小插件,好用) 下载地址: https://r ...
- jQuery.imgLazyLoad图片懒加载组件
一.前言 当一个页面中请求的图片过多,而且图片太大,页面访问的速度是非常慢的,对用户的体验非常不友好:使用图片懒加载,可以减轻服务器的压力,增加页面的访问量,这里主要是总结一下我自己写的图片懒加载组件 ...
- Vue图片懒加载插件
图片懒加载是一个很常用的功能,特别是一些电商平台,这对性能优化至关重要.今天就用vue来实现一个图片懒加载的插件. 这篇博客采用"三步走"战略--Vue.use().Vue.dir ...
- JS实现图片懒加载插件
一.前言 我在前几篇博客的记录中,有说自己在做一个图片懒加载的功能,然后巴拉巴拉的遇到哪些问题,结果做完了也没对懒加载这个功能做一些记录,所以这篇文章主要针对我所实现的思路,以及代码做个记录,实现不佳 ...
- jQuery图片懒加载插件jquery.lazyload.js使用实例注意事项说明
jQuery图片懒加载插件jquery.lazyload.js使用实例注意事项说明 jquery.lazyload.js是一个用JavaScript编写的jQuery插件.它可以延迟加载长页面中的图片 ...
- jQuery插件图片懒加载lazyload
来自XXX的前言: 什么是ImageLazyLoad技术 在页面上图片比较多的时候,打开一张页面必然引起与服务器大数据量的 交互.尤其是对于高清晰的图片,占的几M的空间.ImageLazyLoad技术 ...
随机推荐
- 给springboot增加XSS跨站脚本攻击防护功能
XSS原理 xss攻击的原理是利用前后端校验不严格,用户将攻击代码植入到数据中提交到了后台,当这些数据在网页上被其他用户查看的时候触发攻击 举例:用户提交表单时把地址写成:山东省济南市<scri ...
- 数据结构学习:二叉查找树的概念和C语言实现
什么是二叉查找树? 二叉查找树又叫二叉排序树,缩写为BST,全称Binary Sort Tree或者Binary Search Tree. 以下定义来自百度百科: 二叉排序树或者是一棵空树,或者是具有 ...
- 如何使用apt-get在ubuntu系统上安装OpenJDK 8
文章目录 添加ppa仓库 设置openjdk版本 查看java 版本 Android 8.1 系统编译的时候需要安装OpenJDK 8,这里如果可以自己下载源码编译安装,当然本想编译Android系统 ...
- Vulnhb 靶场系列:Jarbas1.0
靶场镜像 官网 信息收集 攻击机kali IP地址 通过nmap 进行主机发现,发现目标机IP地址 nmap -sP 192.168.227.1/24 参数说明: -sP (Ping扫描) 该选项告诉 ...
- TC SRM498 Div1 1000PT(容斥原理+DP)
[\(Description\)] 网格中每步可以走\((0,\cdots M_x,0\cdots M_y)\)中任意非零向量,有\(K\)种向量不能走,分别是\((r_1,r_1),(r_2,r_2 ...
- Linux --登录用户显示-bash-4.2#解决办法
登录linux系统过后,发现显示的是-bash-4.2# 而不是root@主机名 + 路径的显示方式,发生这种情况的原因是根目录下缺失几个配置文件,从默认配置中拷贝过来就可以解决了: 1 cp /et ...
- jQuery学习笔记——jQuery基础核心
代码风格 在jQuery程序中,不管是页面元素的选择.内置的功能函数,都是美元符号“$”来起始的.而这个“$”就是jQuery当中最重要且独有的对象:jQuery对象,所以我们在页面元素选择或执行功能 ...
- 如何搭建一个WEB服务器项目(一)—— 开篇 ,搭建SSH整合框架
使用Intellij IDEA2019创建SSH(Spring+SpringMVC+Hibernate+Maven整合)项目 观前提示:本系列文章有关服务器以及后端程序这些概念,我写的全是自己的理解, ...
- 学习Echarts:(一)静态图表
Echarts是现在比较火的js图表库,官网有丰富的实例和友好的入门教程.但是图表的种类很多,配置项的参数也很多,一开始我根据图表类型翻看配置项,发现这样学效率太低了,决定先制定一个简单的学习步骤,按 ...
- 前端ie7的兼容问题及解决方案(未完待续)
最近在维护一些老的项目,需要兼容ie7 ,css3就不能用了,这里总结一下碰到的问题及解决方案. 1.盒模型 ie7.8 的盒模型都是 box-sizing为content-box的盒模型,这里在做 ...