【幹貨】設計高性能無限滾動加載,了解高效頁麵秘密
性能測量
同時,也可以使用performance.mark()標記各種時間戳(就像在地圖上打點),保存為各種測量值(測量地圖上的點之間的距離),便可以批量地分析這些數據了。
整體思路和方案設計
滾動問題
用戶體驗優化小竅門
總結一下
。
代碼實現
<div >
<ul >
</ul>
<div ></div>
</div>
<#dataList.forEach(function (v) {#>
<div >
<li>
<a href="<#=v.href#>">
<img src="data:image/gif;base64,R0lGODdhAQABAPAAAP%2F%2F%2FwAAACwAAAAAAQABAEACAkQBADs%3D"
data-src="<#=v.src#>">
data-src="<#=v.src#>">
</img>
<strong><#=v.title#></strong>
<span ><#=v.writer#></span>
<span ><#=v.succNum#></span>
</a>
</li>
</div>
<#})#>
樣式亮點
.slide .img{
display: inline-block;
width: 90px;
height: 90px;
margin: 0 auto;
opacity: 0;
-webkit-transition: opacity 0.25s ease-in-out;
-moz-transition: opacity 0.25s ease-in-out;
-o-transition: opacity 0.25s ease-in-out;
transition: opacity 0.25s ease-in-out; }
(function() { var fetching = false; var page = 1; var slideCache = []; var itemMap = {}; var lastScrollY = window.pageYOffset; var scrollY = window.pageYOffset; var innerHeight; var topViewPort; var bottomViewPort; function isVisible (id) { // ...判斷元素是否在可見區域 } function updateItemCache (node) { // ....更新DOM緩存 } function fetchContent () { // ...ajax請求數據 } function handleDefer () { // ...懶加載實現 } function handleScroll (e, force) { // ...滾動處理程序 } window.setTimeout(handleScroll, 100); fetchContent(); }()); fetchContent(); }());
// 加載中狀態鎖
1)var fetching = false; // 用於加載時發送請求參數,表示第幾屏內容,初始為1,以後每請求一次,遞增1
2)var page = 1;
// 隻緩存最新一次下拉數據生成的DOM節點,即需要插入的dom緩存數組
3)var slideCache = [];
// 用於已經生成的DOM節點儲存,存有item的offsetTop,offsetHeight
4) var slideMap = {};
// pageYOffset設置或返回當前頁麵相對於窗口顯示區左上角的Y位置。
5)var lastScrollY = window.pageYOffset; var scrollY = window.pageYOffset; // 瀏覽器窗口的視口(viewport)高度
6)var innerHeight; // isVisible的上下閾值邊界
7) var topViewPort;
8) var bottomViewPort;
滾動處理程序handleScroll
function handleScroll (e, force) { // 如果時間間隔內,沒有發生滾動,且並未強製觸發加載,則do nothing,再次間隔100毫秒之後
if (!force && lastScrollY === window.scrollY) { window.setTimeout(handleScroll, 100); return;
}
} else { // 更新文檔滾動位置
lastScrollY = window.scrollY;
}
scrollY =
}
scrollY = window.scrollY; // 瀏覽器窗口的視口(viewport)高度賦值
innerHeight = window.innerHeight; // 計算isVisible上下閾值
topViewPort = scrollY - 1000;
bottomViewPort = scrollY + innerHeight +
bottomViewPort = scrollY + innerHeight + 600; // 判斷是否需要加載
// document.body.offsetHeight;返回當前網頁高度
if (window.scrollY + innerHeight + 200 > document.body.offsetHeight) {
fetchContent();
}
fetchContent();
} // 實現懶加載
handleDefer(); window.setTimeout(handleScroll, 100);
}
}
拉取數據
緩存對象
slideCache = [
{
id: "s-97r45",
img: img DOM節點,
node: 父容器DOM node,類似<div ></div>,
src: 圖片資源地址
},
...
]
slideCache由updateItemCache函數更新,主要用於懶加載時的賦值src。這樣我們做到“隻寫入DOM”原則,不需要再從DOM讀取。
function handleDefer () { // 時間記錄
console.time('defer'); // 獲取dom緩存
var list = slideCache; // 對於遍曆list裏的每一項,都使用一個變量,而不是在循環內部聲明。節省內存,把性能高效,做到極致。
var thisImg; for (var i = 0, len = list.length; i < len; i++) {
thisImg = list[i].img; // 這裏我們都是從內存中讀取,而不用讀取DOM節點
var deferSrc = list[i].src; // 這裏我們都是從內存中讀取,而不用讀取DOM節點
// 判斷元素是否可見
if (isVisible(list[i].id)) { // 這個函數是圖片onload邏輯
var handler = function () { var node = thisImg; var src = deferSrc; // 創建一個閉包
return function () {
node.src = src;
node.style.opacity = 1;
}
} var img = new Image();
img.onload = handler();
img.src = list[i].src;
}
} console.timeEnd('defer');
}
主要思路就是對DOM緩存中的每一項進行循環遍曆。在循環中,判斷每一項是否已經進入isVisible區域。如果進入isVisible區域,則對當前項進行真實src賦值,並設置opacity為1。
是否在isVisible區域判斷
function isVisible (id) { var offTop; var offsetHeight; var data; var node; // 判斷此元素是否已經懶加載正確渲染,分為在屏幕之上(已經懶加載完畢)和屏幕外,已經添加到dom中,但是還未請求圖片(懶加載之前) if (itemMap[id]) { // 直接獲取offTop,offsetHeight值 offTop = itemMap[id].offTop; offsetHeight = itemMap[id].offsetHeight; } else { // 設置該節點,並且設置節點屬性:node,offTop,offsetHeight node = document.getElementById(id); // offsetHeight是自身元素的高度 offsetHeight = parseInt(node.offsetHeight); // 元素的上外緣距離最近采用定位父元素內壁的距離 offTop = parseInt(node.offsetTop); } if (offTop + offsetHeight > topViewPort && offTop < bottomViewPort) { return true; } else { return false; } }
性能收益
繼續思考
DOM回收
墓碑(Tombstones)
滾動錨定
總結
顏海鏡
原文地址: https://mp.weixin.qq.com/s/8NoLuPddKimfaiLQbYheBQ
最後更新:2017-06-14 16:31:36