无限长滚动列表(虚拟列表)的实现

无限长滚动列表(虚拟列表)的实现

原理:监听容器滚动,根据滚动距离生成对应列表,再利用绝对定位,将列表展示到容器的对应位置。

1、预先处理容器样式与生成数据

  • 容器列表的最大高度为500px,列表项(li)的高度定为50px,即容器只展示10条数据。
<style>
    ul.container {
      position: relative;
      width:500px;
      max-height: 500px; /* 限定容器展示区域的大小 */
      margin: 0;
      padding: 0;
      border: 1px solid #000;
      overflow-y: auto;
      list-style-type: none;
    }
    ul.container li {
      position: absolute;
      width: 100%;
      height: 50px;
      color: white;
      text-align: center;
      line-height: 50px;
    }
</style>
...
<script>
	const dataList = Array.from({ length: 1000 }).map((item, index) => index); // 生成一千条数据
	const $list = document.querySelector(".container");
	$list.setAttribute("style", `height: ${50 * dataList.length}px;`); // 设置列表的总高度
</script>

2、创建列表项函数

  • 函数功能:根据 i 值切割数据,生成对应的 li 。在首次调用时,渲染前size条数据。
      function createItem(i) {
      	// $list 容器, size为展示数量, i为第一条数据的索引值
        $list.innerHTML = dataList.slice(i, i + size).map(
          item =>
            `<li style="top: ${item * 50}px; background: ${createHexColor()};">${item}</li>`)
          .join("");
      }
  • 要点:i 值(第一条数据的索引值)该如何确定?

3、监听容器滚动确定 i 值

  • 列表的滚动距离(scrollTop)除以列表项(item)的大小,可以确定第一条数据的索引值i。
	  $list.onscroll = handleScroll;
      function handleScroll(e) {
        const i = Math.floor(e.target.scrollTop / 50);
        createItem(i);
      }
  • 监听滚动函数进行节流优化
	 $list.onscroll = throttle(handleScroll, 20);
     function throttle(fn, delay) {
        let lastTime = 0;
        return function (...arg) {
          const nowTime = +new Date();
          if (nowTime - lastTime > delay) {
            fn.apply(this, arg);
            lastTime = nowTime;
          }
        }
      }

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>virtual list</title>
  <style>
    ul.container {
      position: relative;
      width: 500px;
      max-height: 500px;
      /* 限定容器展示区域的大小 */
      margin: 0;
      padding: 0;
      border: 1px solid #000;
      overflow-y: auto;
      list-style-type: none;
    }

    ul.container li {
      position: absolute;
      width: 100%;
      height: 50px;
      color: white;
      text-align: center;
      line-height: 50px;
    }
  </style>
</head>

<body>
  <ul class="container">
  </ul>
  <script>
    const dataList = Array.from({ length: 1000 }).map((item, index) => index); // 生成一千条数据
    createVirtualList(dataList);

    function createVirtualList(dataList) {
      const $list = document.querySelector(".container"); // 生成一千条数据
      $list.setAttribute("style", `height: ${50 * dataList.length}px;`); // 设置列表的总高度
      const size = 20; // 由于列表只展示10条,要让列表可滚动,则需要size大于10
      $list.onscroll = throttle(handleScroll, 20);
      createItem(0);

      function handleScroll(e) {
        const i = Math.floor(e.target.scrollTop / 50);
        createItem(i);
      }

      function createItem(i) {
        $list.innerHTML = dataList.slice(i, i + size).map(
          item =>
            `<li style="top: ${item * 50}px; background: ${createHexColor()};">${item}</li>`)
          .join("");
      }

      function createHexColor() {
        const colorStr = "6789abcdef",
        	len = colorStr.length;
        let colorVal = "#";
        for (let i = 0; i < 6; i++) {
          colorVal += colorStr[Math.floor(Math.random() * len)];
        }
        return colorVal
      }

      function throttle(fn, delay) {
        let lastTime = 0;
        return function (...arg) {
          const nowTime = +new Date();
          if (nowTime - lastTime > delay) {
            fn.apply(this, arg);
            lastTime = nowTime;
          }
        }
      }
    }
  </script>
</body>

</html>
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,以下是一个简单的无限滚动虚拟列表实现。 ``` import React, { useState, useEffect } from 'react'; const ITEM_HEIGHT = 100; // 每个列表项的高度 function VirtualList() { const [items, setItems] = useState([]); const [startIndex, setStartIndex] = useState(0); const [endIndex, setEndIndex] = useState(0); useEffect(() => { const container = document.getElementById('container'); const containerHeight = container.clientHeight; const totalItems = Math.ceil(containerHeight / ITEM_HEIGHT) * 3; // 一屏显示3页列表项 setItems(new Array(totalItems).fill('').map((_, index) => index + 1)); setEndIndex(totalItems - 1); }, []); const handleScroll = () => { const container = document.getElementById('container'); const scrollTop = container.scrollTop; setStartIndex(Math.floor(scrollTop / ITEM_HEIGHT)); setEndIndex(Math.ceil(scrollTop / ITEM_HEIGHT) + Math.ceil(container.clientHeight / ITEM_HEIGHT)); }; return ( <div id="container" style={{ height: '300px', overflowY: 'scroll' }} onScroll={handleScroll}> <div style={{ height: `${items.length * ITEM_HEIGHT}px`, position: 'relative' }}> {items.slice(startIndex, endIndex).map((item) => ( <div key={item} style={{ height: `${ITEM_HEIGHT}px`, position: 'absolute', top: `${item * ITEM_HEIGHT}px` }}> {item} </div> ))} </div> </div> ); } ``` 在上面的代码中,我们通过useState来跟踪当前显示的列表项的起始和结束索引,然后在handleScroll事件中根据滚动条的位置来更新起始和结束索引。我们还使用了useEffect来计算出需要显示的总列表项数,并初始化items状态。在渲染虚拟列表时,我们只渲染当前显示的那些列表项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值