web前端开发中滚动条实现懒加载的流程

已被阅读 2102 次 | 文章分类:日常随笔 | 2021-03-28 17:14

页面中dom元素最大的尺寸无非就是显示器大小,如果请求内容过多,不能全部显示接口数据,常用方式是用表格分页或者滚动条;表格分页是每次请求一部分数据,切换页码再去请求;同样滚动条懒加载的原理是一样的

一 滚动条懒加载数据原理

最后效果是有100条数据,页面div只有能显示十条数据的高度,那么就会出现滚动条,当滚动条滚动到底部,我们再去请求11-20的十条数据,以此类推,所有100条都请求回来后,滚动条不再触发请求事件

其实原理很简单,就是计算什么时候去请求接口;这里需要认识dom元素的三个高度属性:

                                            
const clientHeight = dom.clientHeight;  // 可见区域的高度
const scrollTop = dom.scrollTop;        // 内容被卷起的高度
const scrollHeight = dom.scrollHeight;  // 内容的完整高度
                                            
                                        

为了助于理解 先看下面的效果;

/net/upload/image/20210328/02c318a2-4fe7-475b-ac51-d9f8b55c3626.gif

很直观可以看出来,clientHeight是div容器高度,scrollTop是滚动条往下滚动后被卷起的高度,而scrollHeight包括了可见区域以及上面和下面隐藏区域的所有高度.当被卷起的高度和可见区域的高度之和等于第一次请求的数据个数后,就可以调用执行下一次请求了

/net/upload/image/20210328/66460563-3f22-4311-b50e-a68af05d6b33.jpg

二 滚动懒加载完整代码

代码逻辑基本就是 首先加载前20条数据,如果滚动条拉到底部后,再加载后20条数据;其实跟表格分页功能一样的;每次给后端传当前页和每页数量去请求。这里滚动条滚动一下,就当页数加一。

                                            
<!doctype HTML>
<html>
    <head>
        <meta charset="utf-8"></meta>
        <style>
            html,body{
                width: 100%;
                height: 100%;
               
                padding: 0;
                margin: 0;
            }
         .content{
             position: absolute;
             top:100px;
             left:200px;
            width:200px;
            height:300px;
            background:gray;
            overflow-y: scroll;
            margin-left: 100px;
            border:solid 1px;
         }
         .content p{
             overflow:visible;
             height:20px;
             line-height: 20px;
             padding:0;
             margin:0;
         }
        </style>   
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div class="content" id="content"></div>
        <script>
            let dom=document.getElementById('content');
            dom.innerHTML="";
            let offset=0;
            let limit=20;
            axios.post('http://localhost:80/api/getlazyData', {
                start: 0,
                limit: 20
            }).then(function(res){
                let data=res.data.data;
                data.forEach(ele => {
                    dom.innerHTML+=`<p>${ele}</p>`
                }); 
            })
            dom.addEventListener('scroll',function(){
            const clientHeight = dom.clientHeight;  // 可见区域的高度
            const scrollTop = dom.scrollTop;        // 内容被卷起的高度
            const scrollHeight = dom.scrollHeight;  // 内容的完整高度
                if(scrollTop+clientHeight>=scrollHeight){ 
                    offset+=limit;
                    axios.post('http://localhost:80/api/getlazyData', {
                        start: offset,
                        limit: 20
                    }).then(function(res){
                        let data=res.data.data;
                        data.forEach(ele => {
                            dom.innerHTML+=`<p>${ele}</p>`
                        }); 
                    })

                }
                
            })
        </script>
    </body>
</html>
                                            
                                        

/net/upload/image/20210328/a39725f2-c586-4d1b-8369-1fa0e3f8dde3.gif

其中/api/getlazyData接口是我本地用nodejs模拟的一个接口;

三 nodejs模拟接口

获取前端传过来的起始索引和每次需要加载的数量,然后截取数据返回即可,这里用数组代替;如果要查询数据库就更简单了,用一行select语句就可以实现,代码如下

                                            
// 引入express模块 commonjs规范引入
const express = require('express')
// 实例化 express
const app = express()
// 以能够通过bodyPaser获取req.body
const bodyParser=require("body-parser");
app.use(bodyParser.json())
app.all("*",function(req,res,next){
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Headers", "Content-Type");      //解决Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By",' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
})

let arr=[];
for(let i=0;i<100;i++){ 
    arr.push(`返回值${i}`)
}
let firstIndex=0,lastIndex=0;
app.post("/api/getlazyData", function (req, res) {
    let param=req.body;
    firstIndex=param.start;
    lastIndex+=param.limit;
    let result=arr.slice(param.start,lastIndex);
    if(lastIndex==arr.length+param.limit) lastIndex=0;
    res.send({data:result,msg:'sucess'})
})
// 启动服务器
app.listen(5438, function () {
  console.log("启动服务 http://localhost:5438 ")
})
                                            
                                        

这里配置的是5438端口,而我们页面请求使用的是80;这是因为页面在5055端口启动,浏览器如果直接访问5438,会提示跨域,所以本地用nginx做个反向代理就可,因为服务器是没有同源策略限制的。

                                            
server {
    listen       80;
    server_name  localhost;
    
    #charset koi8-r;

    #access_log  logs/host.access.log  main;
    location /api { 
        proxy_pass http://localhost:5438;
    }
}
                                            
                                        

这样的话,页面请求80端口的/api 接口,就会自动被代理到localhost:5438/api.

QQ:3410192267 | 技术支持 微信:popstarqqsmall

Copyright ©2017 xiaobaigis.com . 版权所有 鲁ICP备17027716号