一、效果图如下

上面的效果图,效果需求如下

1、还没加载图片的时候,默认显示加载图片背景图

2、刚开始进入页面,自动加载第一屏幕的图片

3、下拉界面,当一张图片容器完全显露出屏幕,即刻加载图片,替换背景图

4、加载图片的时候,有渐进显示图片效果

二、难点

1)如何Ajax请求数据

2)如何动态将json数据绑定到html中。

3)如何通过对图片的定位计算,触发图片懒加载机制

4)加分项,显示图片时有渐现的过渡动画

三、前期知识点

1)Ajax相关知识,XMLHttpRequest对象,所有现代的浏览器都支持此对象。

2)innerHTML,数据绑定使用字符串拼接的方式

3)HTML DOM getAttribute() 方法,返回自定属性名的属性值(主要是用于返回自定义属性的属性值)

4)图片的 onload事件,当图片的src属性的属性值为正确(即能成功加载图片),才能触发图片的onload事件

四、难点逐一攻破

  1)如何Ajax请求数据

分四步走

// 1)首先创建一个Ajax对象
var xhr = new XMLHttpRequest;
// 2)打开我们需要请求的数据的那个文件地址
// URL地址后面加随机数目的:清除每一次请求数据时候(get请求)产生的缓存
// 因为每次访问的地址不一样,样浏览器就不会尝试缓存来自服务器的响应,读取本地缓存的数据。
xhr.open('get', 'json/newsList.txt?' + Math.random(), false); // false代表同步
// 3)监听请求的状态
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
var val = xhr.responseText;
jsonData = utils.jsonParse(val);
}
}
// 4)发送请求
xhr.send(null);

  2)如何动态将json数据绑定到html中。

  字符串拼接的方式(数据绑定中最常用的方式),即通过使用innerHTML,对页面元素进行字符串拼接,再重新渲染到页面中

var str = "";
if (jsonData) {
for (var i = 0, len = jsonData.length; i < len; i++) {
var curData = jsonData[i];
str += '<li>';
str += '<div><img src="" trueImg="' + curData["img"] + '"></div>';
str += '<div><h2>' + curData["title"] + '</h2>';
str += '<p>' + curData["desc"] + '</p>';
str += '</div>';
str += '</li></div>';
}
news.innerHTML += str;
}    

  优势:数据绑定最常用的方式,因为浏览器只需要渲染一次(所有模板引擎数据绑定的原理就是字符串拼接,vue、angular、jade、kTemplate.js等等)
                   事先把内容拼接好,最后统一添加到页面中,只引发一次回流

  弊端:我们把新凭借的字符串添加到#ul1中,原有的三个li的鼠标滑过效果都消失了(原来标签绑定的事件都消失了)
                   原来,oUl.innerHTML的作用是把原来的标签以字符串的方式取出,原来作为标签的时候,对应事件绑定的东西已经没有了,然后进行字符串拼接,
                   但是,拼接完成之后,还是字符串!最后再把字符串统一添加到页面中,浏览器还需要把字符串渲染成为对应的标签

  3)如何通过对图片的定位计算,触发图片懒加载机制(最关键点)

  思路:

          A:代表图片距离屏幕顶部的距离 

//这里使用了utils工具类中的offset方法,具体实现看下面源码
var A = utils.offset(curImgPar).offsetTop + curImgPar.offsetHeight;

          B:代表一屏幕距离+滚动条滚动距离

//这里使用了utils工具类中的win方法,具体实现看下面源码
var B = utils.win("clientHeight") + utils.win("scrollTop");

          A < B的时候,此时懒加载的默认图片才能完整显示出来,这个时候就需要触发图片懒加载

  4)加载图片的时候,有渐进显示图片效果

  思路,利用window.setInterval 方法,通过对当前图片的透明度属性(curImg.style.opacity) 从透明0开始到透明度1,变化总时间为500ms即可

// ->实现渐现效果
function fadeIn(curImg) {
var duration = 500, // 总时间
interval = 10, //10ms走一次
target = 1; //总距离是1
var step = (target / duration) * interval; //每一步的步长
var timer = window.setInterval(function () {
var curOp = utils.getCss2SS(curImg, "opacity");
if (curOp >= 1) {
curImg.style.opacity = 1;
window.clearInterval(timer);
return
}
curOp += step;
curImg.style.opacity = curOp;
}, interval);
}

 

五、完整代码

实现懒加载只需要下面3个文件即可,需要请自行拷贝

        1)main.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--做移动端响应式布局页面,都需要加下面的meta-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!--meta:vp+tap一键生成-->
<title>多张图片的延迟加载</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
font-family: "Microsoft Sans Serif";
font-size: 14px;
}
ul, li {
list-style: none;
}
img {
display: block;
border: none;
}
.news {
padding: 10px;
}
.news li {
position: relative;
height: 60px;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.news li > div:first-child { /*意思是,li下面的子div,中的第一个*/
position: absolute;
top: 10px;
left: 0;
width: 75px;
height: 60px;
background: url("./img/loading.PNG") no-repeat center center #e1e1e1;
background-size: 100% 100%;
}
/*移动端布局,最外层容器是不设置宽高的*/ .news li > div:first-child img {
display: none;
width: 100%;
height: 100%;
opacity: 0; /*这里设置为0的目的是,实现渐进的效果,后面的fadeIn函数,作用就是让图片透明都从0变成1*/
} .news li > div:nth-child(2) {
height: 60px;
margin-left: 80px;
}
.news li > div:nth-child(2) h2 {
height: 20px;
line-height: 20px;
/*实现文字超出一行自动裁切*/
overflow: hidden;
text-overflow: ellipsis; /*超出部分省略号显示*/
white-space: nowrap; /*强制不换行*/
}
.news li > div:nth-child(2) p {
line-height: 20px;
font-size: 12px;
color: #616161;
}
</style>
</head>
<body>
<ul id="news" class="news">
<!--<li>-->
<!--<div>-->
<!--<img src="./img/new1.PNG" alt="">-->
<!--</div>-->
<!--<div>-->
<!--<h2>香港四大家族往事,香港四大家族往事,香港四大家族往事</h2>-->
<!--<p>香港四大家族往事:李嘉诚为郑裕彤扶灵香港四大家族往事:李嘉诚为郑裕彤扶灵</p>-->
<!--</div>-->
<!--</li>-->
</ul> <script type="text/javascript" src="./tool/utils.js"></script>
<script type="text/javascript">
var news = document.getElementById("news"),
imgList = news.getElementsByTagName("img"); // 1、获取需要绑定的数据(通过Ajax)
var jsonData = null;
~function () {
// 1)首先创建一个Ajax对象
var xhr = new XMLHttpRequest;
// 2)打开我们需要请求的数据的那个文件地址
// URL地址后面加随机数目的:清除每一次请求数据时候(get请求)产生的缓存
// 因为每次访问的地址不一样,样浏览器就不会尝试缓存来自服务器的响应,读取本地缓存的数据。
xhr.open('get', 'json/newsList.txt?' + Math.random(), false); // false代表同步
// 3)监听请求的状态
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
var val = xhr.responseText;
jsonData = utils.jsonParse(val);
}
}
// 4)发送请求
xhr.send(null);
}();
console.log(jsonData); // 2、数据绑定(使用字符串拼接的方式)
~function () {
var str = "";
if (jsonData) {
for (var i = 0, len = jsonData.length; i < len; i++) {
var curData = jsonData[i];
str += '<li>';
str += '<div><img src="" trueImg="' + curData["img"] + '"></div>';
str += '<div><h2>' + curData["title"] + '</h2>';
str += '<p>' + curData["desc"] + '</p>';
str += '</div>';
str += '</li></div>';
}
news.innerHTML += str;
}
}(); // 3、图片延迟加载
// ->首先实现单张图片的延时加载
function lazyImg(curImg) {
var oImg = new Image;
oImg.src = curImg.getAttribute("trueImg");
oImg.onload = function() {
curImg.src = this.src;
curImg.style.display = "block";
fadeIn(curImg);
oImg = null;
}
curImg.isLoad = true;
} // -> 循环处理每一张图片
function handleAllImg() {
for (var i = 0, len = imgList.length; i < len; i++) {
var curImg = imgList[i];
if (curImg.isLoad) { // 当前图片处理过的话,就不需重新进行处理
continue;
} // ->只有当A小于B的时候再进行处理
// var A = utils.offset(curImg).top + curImg.offsetHeight; // 这里A不能这么计算,因为此时图片是隐藏的,没有图片,他的offsetHeight当让也是为0
// 如果我要的到图片的A值,我们可以通过拿到他父节点的容器就行了,哈哈
var curImgPar = curImg.parentNode,
A = utils.offset(curImgPar).offsetTop + curImgPar.offsetHeight,
B = utils.win("clientHeight") + utils.win("scrollTop");
if (A < B) {
lazyImg(curImg);
}
}
} // ->实现渐现效果
function fadeIn(curImg) {
var duration = 500, // 总时间
interval = 10, //10ms走一次
target = 1; //总距离是1
var step = (target / duration) * interval; //每一步的步长
var timer = window.setInterval(function () {
var curOp = utils.getCss2SS(curImg, "opacity");
if (curOp >= 1) {
curImg.style.opacity = 1;
window.clearInterval(timer);
return
}
curOp += step;
curImg.style.opacity = curOp;
}, interval);
} // 4、开始的时候(过500ms)加载1屏幕的图片,当滚动条滚动的时候,加载其他图片
window.setTimeout(handleAllImg, 500);
window.onscroll = handleAllImg; </script>
</body>
</html>

  

  2)utils.js

// 为了与全局变量冲突,我们使用单例模式
var utils = {
// jsonParse: 把JSON格式的字符串转化为JSON格式的对象
jsonParse: function (str) {
var val = null;
try {
val = JSON.parse(str);
} catch (e) {
val = eval('(' + str + ')');
}
return val;
}, getCss2SS : function(curEle, attr) {
var val = null, reg = null;
if ('getComputedStyle' in window) {
val = window.getComputedStyle(curEle, null)[attr];
} else {
if (attr === 'opacity') {
val = curEle.currentStyle[attr]; // ->返回 alpha(opacity=10)
reg = /^alpha\(opacity=(\d+(?:\.\d+)?)\)$/i; // 获取10这个数字
val = reg.test(val)?reg.exec(val)[1]/100:1 // 超厉害,test与exec一起使用!!!
}
val = curEle.currentStyle[attr];
}
reg = /^-?\d+(\.\d+)?(px|pt|rem|em)?$/i; //匹配的情况:纯数值或者带单位的数值
return reg.test(val) ? parseFloat(val) : val;
}, offset : function(curEle) {
var totalLeft = null,
totalTop = null,
par = curEle.offsetParent;
// 首先把自己本身的进行累加
totalLeft += curEle.offsetLeft;
totalTop += curEle.offsetTop; while (par) {
if (navigator.userAgent.indexOf("MSIE 8.0") === -1) {
// 累加父级参照物边框
totalTop += par.clientTop;
totalLeft += par.clientLeft;
}
// 累加父级参照物本身的偏移
totalTop += par.offsetTop;
totalLeft += par.offsetLeft;
par = par.offsetParent;
}
console.log('offsetTop: ' + totalTop + ', offsetLeft: ' + totalLeft);
var result = {};
result.offsetTop = totalTop;
result.offsetLeft = totalLeft;
return result;
}, win : function(attr, value) {
if (value === undefined) {
return document.documentElement[attr] || document.body[attr];
}
document.documentElement[attr] = value;
document.body[attr] = value;
}
};

3、json文件

[{"img":"./img/new1.PNG", "title": "1网络强国战略与“十三五”十四大战略", "desc": "1互联网是二十世纪人类最大的发明,互联网是二十世纪人类最大的发明"},
{"img":"./img/new2.PNG", "title": "2网络强国战略与“十三五”十四大战略", "desc": "2互联网是二十世纪人类最大的发明,互联网是二十世纪人类最大的发明"},
{"img":"./img/new3.PNG", "title": "3网络强国战略与“十三五”十四大战略", "desc": "3互联网是二十世纪人类最大的发明,互联网是二十世纪人类最大的发明"}
]

【JavaScript】使用纯JS实现多张图片的懒加载(附源码)的更多相关文章

  1. JS怎样实现图片的懒加载以及jquery.lazyload.js的使用

    在项目中有时候会用到图片的延迟加载,那么延迟加载的好处是啥呢? 我觉得主要包括两点吧,第一是在包含很多大图片长页面中延迟加载图片可以加快页面加载速度:第二是帮助降低服务器负担. 下面介绍一下常用的延迟 ...

  2. js 函数的多图片懒加载(lazy) 带插件版完整解析

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS实现图片懒加载效果 页面需求 1 ...

  3. 「Vue.js」Vue-Router + Webpack 路由懒加载实现

    一.前言 当打包构建应用时,Javascript 包会变得非常大,影响页面加载.如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了.结合 Vue ...

  4. 纯JS 10分钟 实现图片懒惰加载

    知识点: 1:h5 新增选择器  document.querySelectorAll 2:JS 经典,防抖 3:距离判断:getBoundingClientRect  思路:通过浏览器滚动事件, 判断 ...

  5. swiper.js 多图片页面的懒加载lazyLoading

    swiper.js官网:http://www.swiper.com.cn/api/Images/2015/0308/213.html 设为true开启图片延迟加载,使preloadImages无效.需 ...

  6. arcgis api 3.x for js入门开发系列九热力图效果(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  7. arcgis api 3.x for js 入门开发系列八聚合效果(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  8. arcgis api 3.x for js 入门开发系列三地图工具栏(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  9. arcgis api 3.x for js 入门开发系列十一地图统计图(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

随机推荐

  1. 51nod 1060 最复杂的数(数论,反素数)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1060 题解:可以去学习一下反素数. #include < ...

  2. hud 1633 Orchard Trees 点是否在三角形内模板 *

    Orchard Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  3. 【Offer】[51] 【数组中的逆序对】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如,在数组 ...

  4. Airflow: TypeError can't pickle memoryview objects

    apache-airflow1.9.0 + python3 + rabbitmq + librabbitmq2.0.0 相关配置如下: broker_url = amqp://cord:123456@ ...

  5. charles 发布Glist

    本文参考:charles 发布Glist Publish Gist /发布代码段 选中某个文件,点击Publish Gist,如果你没有github,这个文件将被匿名发布,您也就无法删除它: 当然你可 ...

  6. [PySpark] 01 - Preview parquet files in S3 ×××

    本系列基于实际测试数据,质量保证,不自欺欺人. 实践是检验真理的唯一标准. Swipejobs is all about matching Jobs to Workers. Your challeng ...

  7. Beescms_v4.0 sql注入漏洞分析

    Beescms_v4.0 sql注入漏洞分析 一.漏洞描述 Beescms v4.0由于后台登录验证码设计缺陷以及代码防护缺陷导致存在bypass全局防护的SQL注入. 二.漏洞环境搭建 1.官方下载 ...

  8. Linux系统在开机的时候自动启动SVN

    Linux系统在开机的时候自动启动SVN 1.创建执行脚本svn.sh(/root路径下,随便哪个路径),其内容很简单,如下: #!/bin/bash     svnserve -d --listen ...

  9. Tomcat启动报错java.lang.ClassNotFoundException: javax.el.ExpressionFactory

    严重: Context initialization failedorg.springframework.beans.factory.BeanCreationException: Error crea ...

  10. Salem and Sticks-萨鲁曼的棍子 CodeForce#1105A 暴力

    题目链接:Salem and Sticks 题目原文 Salem gave you