前端开发攻略---模拟后端接口返回数据,教你三种方式实现滚动到底部加载更多数据

本文详细比较了手动监听滚动事件、使用IntersectionObserverAPI以及借助插件实现滚动加载更多数据的原理、优缺点和代码示例,帮助开发者选择合适的方法。
摘要由CSDN通过智能技术生成

目录

1、演示

 2、方式一:手动监听滚动事件

原理:

优点:

缺点:

实现代码:

代码解析:

3、 方式二:使用原生的Intersection Observer API

原理:

优点:

缺点:

实现代码:

代码解析:

4、方式三:使用插件 

原理:

优点:

缺点:

实现代码:

代码解析:


1、演示

 2、方式一:手动监听滚动事件

原理:

手动监听滚动事件的原理是通过添加滚动事件监听器,当页面滚动时触发相应的回调函数,检测页面是否已经滚动到底部,从而触发加载更多数据的逻辑。

优点:

1、相对简单直接:不需要引入额外的插件或API,只需编写少量代码即可实现滚动加载更多功能。

2、可定制性强:可以根据项目需求灵活地调整滚动加载更多的逻辑,比如添加动画效果、加载提示等。

缺点:

1、性能问题:由于滚动事件触发频率较高,在数据量较大时可能会导致性能问题,需要额外的优化措施来提高性能。

2、兼容性问题:不同浏览器的滚动事件表现可能不尽相同,需要考虑浏览器兼容性。

3、实现复杂度:相比起使用现成的插件或API,手动监听滚动事件需要编写更多的代码。

实现代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      .loadingText {
        width: 100%;
        text-align: center;
        height: 50px;
        font-size: 50px;
        align-items: center;
      }
      .item {
        font-size: 50px;
        padding: 50px;
        width: 100%;
        background-color: rgb(71, 70, 70);
        text-align: center;
        margin-bottom: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container"></div>
    <p class="loadingText">正在加载...</p>
  </body>
  <script>
    const container = document.querySelector('.container')
    const loadingText = document.querySelector('.loadingText')

    const body = {
      pageSize: 10,
      pageNum: 1,
    }
    let data = []
    const total = 25
    function getData() {
      let maxNum = body.pageNum * body.pageSize
      let startNum = (body.pageNum - 1) * body.pageSize + 1
      let endNum = maxNum > total ? total : maxNum
      for (let i = startNum; i <= endNum; i++) {
        data.push(i)
      }
      renderPage()
    }

    function renderPage() {
      container.innerHTML = ''
      for (let i = 0; i < data.length; i++) {
        const div = document.createElement('div')
        div.innerText = data[i]
        div.classList = 'item'
        container.appendChild(div)
      }
    }

    let timer = null
    document.addEventListener('scroll', function (e) {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        var contentHeight = document.documentElement.scrollHeight || document.body.scrollHeight
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        var windowHeight = document.documentElement.clientHeight || document.body.clientHeight
        if (contentHeight - scrollTop - windowHeight <= 0) {
          if (body.pageNum >= Math.ceil(total / body.pageSize)) {
            loadingText.innerHTML = '没有更多了'
            return
          } else {
            body.pageNum++
            getData()
          }
        }
      })
    })

    window.onload = function () {
      getData()
    }
  </script>
</html>

代码解析:

1、定义body模拟后端所需参数,pageSize表示一次加载多少条数据,pageNum表示第几次加载数据

2、定义data数据

3、定义total模拟通过调用接口后端返回的数据总条数

4、getData函数模拟从后端获取数据

5、renderPage函数用来将数据渲染到页面上

最后通过监听页面的滚动事件,当用户滚动页面时,会触发该事件。在事件处理函数中,首先会清除之前设置的定时器timer,然后再设置一个新的定时器。这样做是为了防止在用户不断滚动页面时频繁触发事件处理函数。

在定时器中,首先获取页面内容的高度、滚动距离和窗口高度。然后判断用户是否已经滚动到页面底部,即页面内容高度减去滚动距离和窗口高度的差值是否小于等于0。如果是,则判断当前页面页数是否已经达到总页数,如果是,则显示"没有更多了"的提示信息,否则增加页数并继续获取数据。

3、 方式二:使用原生的Intersection Observer API

原理:

通过监视指定元素与视口交叉的情况,当指定元素进入或离开视口时触发相应的回调函数。通过使用Intersection Observer API,可以实现监听滚动事件,从而触发加载更多数据的功能。

优点:

1、高性能:Intersection Observer API可以节省性能资源,因为它只在元素进入或离开视口时触发相关回调函数,相比手动监听滚动事件性能更好。

2、良好的浏览器支持:Intersection Observer API的浏览器支持较好,可以在大多数主流浏览器中使用。

3、灵活性:可以通过配置选项灵活地调整触发时机和回调函数,满足不同项目需求。

缺点:

1、相对复杂:相比手动监听滚动事件,使用Intersection Observer API需要理解一定的API和相关概念,相对复杂一些。

2、兼容性问题:虽然大多数主流浏览器支持Intersection Observer API,但仍有部分浏览器可能存在兼容性问题,需要进行兼容性处理。

实现代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .loadingText {
        width: 100%;
        text-align: center;
        height: 50px;
        font-size: 50px;
        align-items: center;
      }
    </style>
  </head>
  <body>
    <div class="container"></div>
    <p class="loadingText">正在加载...</p>
  </body>
  <script>
    const container = document.querySelector('.container')
    const loadingText = document.querySelector('.loadingText')

    const body = {
      pageSize: 10,
      pageNum: 1,
    }
    let data = []
    const total = 25
    function getImgData() {
      let maxNum = body.pageNum * body.pageSize
      let startNum = (body.pageNum - 1) * body.pageSize + 1
      let endNum = maxNum > total ? total : maxNum
      for (let i = startNum; i <= endNum; i++) {
        data.push(`https://img.beiqiai.com/img${i}.jpg`)
      }
      renderPage()
    }

    function renderPage() {
      container.innerHTML = ''
      for (let i = 0; i < data.length; i++) {
        const img = document.createElement('img')
        img.src = data[i]
        container.appendChild(img)
      }
    }

    const observer = new IntersectionObserver(entries => {
      // 遍历观察到的所有元素
      entries.forEach(entry => {
        // 如果当前元素进入视口
        if (entry.isIntersecting) {
          if (body.pageNum > Math.ceil(total / body.pageSize)) {
            loadingText.innerHTML = '没有更多了'
            observer.unobserve(loadingText)
            return
          } else {
            getImgData()
            body.pageNum++
          }
        }
      })
    })

    observer.observe(loadingText)
  </script>
</html>

代码解析:

总体思路不变,将方式一种的监听滚动事件换成使用IntersectionObserver来进行监听

在这里使用IntersectionObserver创建了一个观察器实例,并使用它来观察具有id "loadingText"的元素。当被观察的元素进入视口时,代码会检查当前页面数是否超过基于总项目数和页面大小计算得出的总页数。如果是这样,它会更新加载文本以指示没有更多项目可以加载,并停止观察该元素。否则,它调用getImgData()函数加载更多图像数据,并递增页面数。

4、方式三:使用插件 

原理:

使用Element组件库中的Infinite Scroll 无限滚动插件。

优点:

1、快速实现:使用无限滚动插件可以快速实现滚动加载更多功能,节省开发时间和精力。

2、配置灵活:插件提供了丰富的配置选项,可以根据项目需求灵活定制加载更多数据的行为。

3、通用性:无限滚动插件通常具有良好的通用性,可以在多个项目中复用。

缺点:

1、依赖第三方插件:使用无限滚动插件需要依赖第三方库或插件,可能会增加项目的复杂度。

2、定制性受限:虽然插件提供了丰富的配置选项,但某些特定的定制需求可能无法通过插件满足,需要额外的工作。

3、性能问题:一些无限滚动插件可能存在性能问题,特别是在处理大量数据时,需要进行优化。

实现代码:

<template>
  <ul v-infinite-scroll="load" class="infinite-list" style="overflow: auto">
    <li v-for="i in count" :key="i" class="infinite-list-item">{{ i }}</li>
  </ul>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
const count = ref(0)
const load = () => {
  count.value += 2
}
</script>

<style>
.infinite-list {
  height: 300px;
  padding: 0;
  margin: 0;
  list-style: none;
}
.infinite-list .infinite-list-item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50px;
  background: var(--el-color-primary-light-9);
  margin: 10px;
  color: var(--el-color-primary);
}
.infinite-list .infinite-list-item + .list-item {
  margin-top: 10px;
}
</style>

代码解析:

通过使用v-infinite-scroll指令,当滚动到列表底部时调用load方法来加载更多数据。初始时列表为空,通过循环遍历count来显示对应数量的列表项。每次调用load方法时,count增加2,从而增加2个列表项。

在样式部分,.infinite-list设置了高度和样式,在.infinite-list .infinite-list-item中设置了每个列表项的样式,包括高度、背景色、边距和文字颜色。.infinite-list .infinite-list-item + .list-item用来给列表项之间添加间距。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bbamx.

谢谢您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值