前景
通常后端数据返回都会对内容较多的数据进行分页处理,前台只需要传递相关分页标识就可以了。可是这种情况常见于B端的表格展示,那么若我们要做到类似于C端的多数据分批加载有什么响应的处理方式呢?
常见的情况有: 图片懒加载,多数据列表加载
解决思路
为了前端优化,避免一次性加载过多数据的页面渲染,从而导致的页面卡顿问题,通常会只加载一部分数据,然后通过滚动事件,判断触发点是否出现在可视区域,从而二次发送请求
其中,触发点的元素:可以是骨架屏;也可以在加载列表的底部添加一个div元素(height:0px)
实现方法
1. 滚动监听+scrollTop+offsetTop+clientHeight
判断dom顶部是否出现在可视化区域:clientHeight+scrollTop>=元素.offsetTop
例如:图片懒加载。img在没有src属性的时候,是不会对资源进行加载的,其中data-url是自定义属性
<body>
<img src="./img/pixel.gif" data-url="./img/1.jpeg">
<img src="./img/pixel.gif" data-url="./img/2.jfif">
<img src="./img/pixel.gif" data-url="./img/3.jfif">
<img src="./img/pixel.gif" data-url="./img/4.jfif">
<img src="./img/pixel.gif" data-url="./img/5.jfif">
<img src="./img/pixel.gif" data-url="./img/6.webp">
<script>
let imgs = document.getElementsByTagName('img')
// 1. 一上来立即执行一次
fn()
// 2. 监听滚动事件
window.onscroll = lazyload(fn, true)
function fn() {
// 获取视口高度和内容的偏移量
let clietH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
for (let i = 0; i < imgs.length; i++) {
let x = scrollTop + clietH - imgs[i].offsetTop //当内容的偏移量+视口高度>图片距离内容顶部的偏移量时,说明图片在视口内
if (x > 0) {
imgs[i].src = imgs[i].getAttribute('data-url'); //从dataurl中取出真实的图片地址赋值给url
}
}
}
// 函数节流
function lazyload(fn, immediate) {
let timer = null
return function () {
let context = this;
if (!timer) {
timer = setTimeout(() => {
fn.apply(this)
timer = null
}, 200)
}
}
}
</script>
</body>
————————————————
版权声明:本文为CSDN博主「望屿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/darabiuz/article/details/123151266
2. getBoundingClientRect()
getBoundingClientRect()是获取当前dom元素的相对位置,可获取x,y轴的距离
可视区域的触发点:bound.top<=clientHeight
3. intersectionObserver(浏览器的observer)
这里以react写法举例:
const scrollRef = useRef(null);
// 当我的 ref 的 div 到顶的时候,我们进行切换。
// 如何判断到顶了?
// 1. getBoundingClientRect();
// 2. IntersectionObserver();
useEffect(()=>{
var intersectionObserver = new IntersectionObserver((entries) => {
console.log(entries[0].isIntersecting);//该值标识是否出现在可视区域
onChange && onChange(entries[0].isIntersecting)//此处可以对数据进行二次请求操作
});
intersectionObserver.observe(scrollRef.current);
return () => {
intersectionObserver.unobserve(scrollRef.current);
intersectionObserver = void 0;
}
}, [])
4. 正对百万级数据的渲染加载(一般不会有这种场景)
1. 虚拟长列表:仅仅在可视化视图区域渲染dom
参考文章:blog.csdn.net/qq_43307723…
2. worker :拆分线程
我理解的意思大概就是说,js是一个单线程,web worker可以分离一个子线程出来,然后将需要大量计算的那部分代码放在这个子线程中去执行,子线程相对于主线程互相独立,所以不会影响到主线程ui的正常渲染,减少了代码阻塞。
worker使用详情:www.ruanyifeng.com/blog/2018/0…
worker的具体运用参考:juejin.cn/post/684490…
额外知识点补充
浏览器的5种observer
** intersectionObserver **:监听一个元素在可视区域的可见性(场景:某元素滚动到xx时,顶部菜单变成浮动固定)
mutationObserve:监听一个元素,子节点的增删改
** resizeObserver **:监听一个元素宽高的改变(运用场景:echarts图表resize动态响应失效的时候,可以尝试这种方式)
performanceObserver:浏览器performance记录数据行为的监听
reportingObserver:对浏览器自动提示的一些警告,干预等行为进行监听