图片懒加载的原理是什么?
首先明白为什么要懒加载:
懒加载即延迟,对于图片过多的页面,为了加快页面加载速度,我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。
这样一来页面加载性能大幅提升,提高了用户体验。
注:手机会自动做懒加载
实现原理:
在页面载入时将img标签內的src指向一个小图片,即占位图或loading图,将真实地址存放于一个自定义属性data-src中。当页面滚动时,遍历有data-src的img标签,判断每个img是否进入可视区,当某个img进入了可视区域,就将真实地址赋值给该img的src并将该img的data-src删除以避免重复判断。
核心代码:
<img src="https://i.loli.net/2017/08/08/5989307b6c87b.gif" data-xxx="${data.content[i].url}">
let images = document.querySelectorAll('img[data-xxx]')
for(let i = 0; i <images.length; i++){
if(出现在屏幕里(images[i])){
images[i].src = images[i].getAttribute('data-xxx')
images[i].removeAttribute('data-xxx')
}
预加载:
预先加载所需资源
<link rel="prefetch" href="https://i.loli.net/2017/08/08/5989307b6c87b.gif">
全部代码:
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<title>加载更多 Demo</title>
<link rel="prefetch" href="https://i.loli.net/2017/08/08/5989307b6c87b.gif">
<style>
*{padding:0; margin: 0; box-sizing: border-box;}
*::before{box-sizing: border-box;}
*::after{box-sizing: border-box;}
ul,ol{list-style:none;}
#list{
max-width: 680px;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
#list > li{
width: calc(33.333333% - 10px);
}
#list > li img{
width: 100%;
}
.loadMore{
text-align: center; margin: 16px 0;
}
.oneToOne{
padding-top: 100%;
position: relative;
}
.oneToOne img{
position: absolute;
width: 100%;
height: 100%;
left: 0; top: 0;
}
</style>
</head>
<body>
<ol id=list>
</ol>
<div class=loadMore>
<button id="loadMoreButton" class=button>加载更多</button>
<div style="height: 1000px;"></div>
</div>
<script>
let list = document.querySelector('#list')
for(var i=0; i<9; i++){
let li = document.createElement('li')
let div = document.createElement('div')
div.className = 'oneToOne'
let img = document.createElement('img')
div.appendChild(img)
img.src = '//via.placeholder.com/200x200?text=' + Math.random().toFixed(6)
let p = document.createElement('p')
p.textContent = `这是第 ${i+1} 段话`
li.appendChild(div)
li.appendChild(p)
list.appendChild(li)
}
let n = 1
let hasNext = true
let 正在请求 = false
function loadMore(){
if(正在请求){return}
if(!hasNext){ return }
let request = new XMLHttpRequest()
request.open('GET', `./page-${n+1}.html`)
request.onerror = function(){ 正在请求 = false }
request.onload = function(){
正在请求 = false
n += 1
let response = request.responseText
// JSON.parse 输入符合 JSON 语法的字符串,输出 JSON 对应的数据 array/number/string
let data = window.JSON.parse(response)
for(let i = 0; i< data.content.length; i++){
let liString = `
<li>
<div class=oneToOne>
<img src="https://i.loli.net/2017/08/08/5989307b6c87b.gif" data-xxx="${data.content[i].url}">
</div>
<p>${data.content[i].text}</p>
</li>
`
list.insertAdjacentHTML( 'beforeend', liString );
}
if(data.hasNextPage === false){
hasNext = false
loadMoreButton.textContent = '没了'
}
}
正在请求 = true
request.send()
}
loadMoreButton.onclick = loadMore
window.onscroll = function(){
if(出现在屏幕里(loadMoreButton) === true){
//loadMoreButton.click()
if(hasNext){ loadMore() }
}
let images = document.querySelectorAll('img[data-xxx]')
for(let i = 0; i <images.length; i++){
if(出现在屏幕里(images[i])){
images[i].src = images[i].getAttribute('data-xxx')
images[i].removeAttribute('data-xxx')
}
}
}
function 出现在屏幕里(element){
var doc = document.documentElement;
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
var viewport的高度 = doc.clientHeight
var viewportOffset = element.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var 按钮到viewport顶部的距离 = viewportOffset.top;
if(按钮到viewport顶部的距离 <= viewport的高度){
return true
}else{
return false
}
}
</script>
</body>
</html>
<style>
.button {
border: none;
background: #3498db;
background-image: linear-gradient(to bottom, #3498db, #2980b9);
border-radius: 28px;
color: #ffffff;
font-size: 20px;
padding: 10px 20px 10px 20px;
text-decoration: none;
}
.button:hover {
background: #3cb0fd;
background-image: linear-gradient(to bottom, #3cb0fd, #3498db);
text-decoration: none;
}
</style>