一、效果圖如下

上面的效果圖,效果需求如下
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互聯網是二十世紀人類最大的發明,互聯網是二十世紀人類最大的發明"}
]
