优点:防止页面一次性向服务器发送大量请求,导致服务器响应面,页面卡顿崩溃等
懒加载函数
function lazyAll(options = { lazybox: [], showOffset: 150, throttleTime: 100, imgtruestr: 'lazyimg' }) {
//lazybox //所有图片元素。必须有高度,可以用加载图,不给高度也可以,但是会有停顿
// showOffset 图片底部距离底部多高就开始加载, 越大越早加载
// throttleTime 节流时间
//开始加载
const { lazybox, showOffset, throttleTime, imgtruestr } = options
const singlelazy = (lazyimg) => {
let trueimg = lazyimg.getAttribute(imgtruestr)
lazyimg.style.opacity = 0.5
lazyimg.src = trueimg //替换真实图片
lazyimg.onload = () => {
lazyimg.style.opacity = 1
lazyimg.style.transition = 'all 0.3s';
//加载成功则不透明了
}
lazyimg.setAttribute('isload', true)
//添加一个加载成功的标识
}
//节流函数
function throttle(func, delay) {
var prev = Date.now();
return function () {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
const lazyBoot = (lazyimgArr) => {
let B = document.documentElement.clientHeight
lazyimgArr = Array.from(lazyimgArr)
for (let index = 0; index < lazyimgArr.length; index++) {
let lazyimg = lazyimgArr[index];
if (lazyimg.getAttribute('isload') === 'true') continue //已经加载过了
let A = lazyimg.getBoundingClientRect().bottom //元素距离底部的高度
if (A <= (B + showOffset)) {
// console.log(lazyimg.children)
singlelazy(lazyimg)
}
}
}
//初始化执行一次
setTimeout(() => {
lazyBoot(lazybox)
}, 500)
window.onscroll = throttle(() => {
lazyBoot(lazybox)
}, throttleTime)
}
let lazybox = document.querySelectorAll('.lazybox > img')
lazyAll({ lazybox: lazybox, showOffset: 100, throttleTime: 100, imgtruestr: 'lazyimg' })
<div class="lazybox">
<img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3286238346,2636386852&fm=26&gp=0.jpg" alt=""
lazyimg='https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1359446852,3171321292&fm=26&gp=0.jpg'>
</div>
触底加载
html
//将该元素至于列表底部,只要该元素出现在视口,即可触发回调
<div id='more'>loading...<div>
js
let loadMore = () => {
let oboptions = {
threshold: [0] //可以给0 - 1 之间的数 0 元素刚进入窗口 1 完全进入窗口
}
let ob = new IntersectionObserver(async changes => {
let item = changes[0] //监听的所有对象。这里触底加载我们只监听了一个元素
if (item.isIntersecting) {//元素刚好进入视口
//加载更多
let res = await Promise.resolve('xxx')
//重新获取所有的图片元素
if (res == 'xxx') { //满足一定条件,解除
ob.unobserve(document.getElementById('more'))
}
console.log(res)
}
}, oboptions)
ob.observe(document.getElementById('more'))
}
loadMore()
IntersectionObserver 监听某个元素和视口交叉的状态
//该api判断的以矩形条件为例的
有兼容性问题,请使用babel
new IntersectionObserver(
entries.forEach(entry=>{
}),
{
threshold: [0, 0.25, 0.5, 0.75, 1] //0%、25%、50%、75%、100% 可见时,触发回调多次回调,传一个就好
// [0, 0.5, 1],表示在两个矩形开始相交,相交一半,完全相交这三个时刻都要触发一次回调函数。如果你传了个空数组,它会给你自动插入 0,变成 [0],也等效于默认值 0
//不仅当目标元素从视口外移动到视口内时会触发回调,从视口内移动到视口外也会:需要加载完毕后,立刻移除监听,免得再次触发渲染
root:null,//不填则默认为浏览器窗口
rootMargin:'100px 0px'//放大了根元素的区域 这里相当于加大了浏览器的上margin 和 下margin 图片加载会更提前,只能用px和百分比 em会报错
}
).observe(监听的元素)
observer.disconnect(); //终止对所有可见元素的变化观察
性能比较好,该api默认是异步的,并且监听元素是默认去重的
let lazybox = document.querySelectorAll('.lazybox > img')
const singlelazy = (lazyimg) => {
let trueimg = lazyimg.getAttribute('lazyimg')
lazyimg.style.opacity = 0.5
lazyimg.src = trueimg //替换真实图片
lazyimg.onload = () => {
lazyimg.style.opacity = 1
lazyimg.style.transition = 'all 0.3s';
//加载成功则不透明了
}
}
const lazyAllImage = () => {
let oboptions = {
threshold: [0.2]
}
//注意 如果异步加载数据,该对象只能存在一个,可以提出来单独用ob
let ob = new IntersectionObserver(changes => {
console.log(changes) //所有被监听到的盒子 并且默认是去重
changes.forEach(item => {
let { isIntersecting, target } = item
if (isIntersecting) {
singlelazy(target)
ob.unobserve(target)
}
})
}, oboptions);
//每次异步数据。这里要重新添加监听的对象
[].forEach.call(lazybox, box => {
ob.observe(box)
})
}
lazyAllImage()