通过交叉实现数据触底分页效果new IntersectionObserver()(html、react、vue2、vue3)中使用

react中用法

TypeScript 复制代码
import React, { useState, useEffect, useRef } from 'react';

const InfiniteScroll = () => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(1);
  const loaderRef = useRef(null);

  // 模拟加载更多数据的函数
  const loadMoreData = () => {
    if (loading) return; // 防止重复加载
    setLoading(true);

    // 模拟异步数据请求
    setTimeout(() => {
      const newItems = Array.from({ length: 10 }, (_, index) => `Item ${(page - 1) * 10 + index + 1}`);
      setItems((prevItems) => [...prevItems, ...newItems]);
      setPage((prevPage) => prevPage + 1);
      setLoading(false);
    }, 1000); // 模拟请求延时
  };

  useEffect(() => {
    // 创建 IntersectionObserver
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          loadMoreData(); // 当加载元素进入视口时,触发加载更多数据
        }
      },
      {
        rootMargin: '0px', // 可根据需要调整,决定何时触发
        threshold: 1.0, // 触发条件:元素完全进入视口
      }
    );

    // 启动观察
    if (loaderRef.current) {
      observer.observe(loaderRef.current);
    }

    // 清理 observer
    return () => {
      if (loaderRef.current) {
        observer.unobserve(loaderRef.current);
      }
    };
  }, [loading, page]);

  return (
    <div>
      <div>
        {items.map((item, index) => (
          <div key={index}>{item}</div>
        ))}
      </div>
      {/* 触底加载元素 */}
      <div ref={loaderRef}>
        {loading ? <p>Loading...</p> : <p>Scroll down to load more...</p>}
      </div>
    </div>
  );
};

export default InfiniteScroll;

原生js中用法

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinite Scroll with IntersectionObserver</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 0;
            margin: 0;
            height: 2000px; /* Just to make the page scrollable */
        }
        .item {
            padding: 10px;
            margin: 10px 0;
            background-color: #f4f4f4;
            border: 1px solid #ddd;
        }
        #loading {
            text-align: center;
            padding: 10px;
            background-color: #f1f1f1;
        }
    </style>
</head>
<body>
    <div id="content">
        <!-- 初始内容 -->
        <div class="item">Item 1</div>
        <div class="item">Item 2</div>
        <div class="item">Item 3</div>
        <div class="item">Item 4</div>
        <div class="item">Item 5</div>
    </div>
    
    <!-- 加载更多的提示 -->
    <div id="loading">Loading more...</div>

    <script>
        // 模拟加载更多数据的函数
        let page = 1;
        const loadMoreData = () => {
            // 模拟异步请求数据
            setTimeout(() => {
                const content = document.getElementById('content');
                for (let i = 0; i < 5; i++) {
                    const newItem = document.createElement('div');
                    newItem.classList.add('item');
                    newItem.textContent = `Item ${page * 5 + i + 1}`;
                    content.appendChild(newItem);
                }
                page++;
            }, 1000); // 模拟1秒的延迟
        };

        // 设置 IntersectionObserver 监听"加载更多"元素
        const loadingElement = document.getElementById('loading');

        const observer = new IntersectionObserver((entries, observer) => {
            // 只在元素完全进入视口时触发
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    loadMoreData();
                    observer.unobserve(loadingElement); // 停止监听当前元素
                    observer.observe(loadingElement); // 重新开始监听
                }
            });
        }, {
            rootMargin: '0px',
            threshold: 1.0 // 完全进入视口时触发
        });

        // 启动 IntersectionObserver
        observer.observe(loadingElement);
    </script>
</body>
</html>

Vue2中使用

TypeScript 复制代码
<template>
  <div>
    <!-- 内容部分 -->
    <div class="content">
      <div v-for="(item, index) in items" :key="index" class="item">
        {{ item }}
      </div>
    </div>

    <!-- 加载更多提示 -->
    <div id="loading" class="loading">加载更多...</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: ['Item 1', 'Item 2', 'Item 3'], // 初始数据
      page: 1, // 当前页数
    };
  },
  mounted() {
    // 设置 IntersectionObserver 监听加载更多区域
    const loadingElement = document.getElementById('loading');
    const observer = new IntersectionObserver(this.handleIntersection, {
      rootMargin: '0px',
      threshold: 1.0, // 完全进入视口时触发
    });
    observer.observe(loadingElement);
  },
  methods: {
    handleIntersection(entries, observer) {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // 如果加载更多区域进入视口,加载更多数据
          this.loadMoreData();
        }
      });
    },
    loadMoreData() {
      setTimeout(() => {
        const newItems = Array.from({ length: 5 }, (_, i) => `Item ${this.page * 5 + i + 1}`);
        this.items.push(...newItems); // 添加新数据
        this.page += 1; // 增加页码
      }, 1000); // 模拟网络请求延时
    },
  },
};
</script>

<style>
.content {
  height: 1500px; /* 让页面滚动 */
}

.item {
  padding: 10px;
  margin: 10px 0;
  background-color: #f4f4f4;
  border: 1px solid #ddd;
}

.loading {
  text-align: center;
  padding: 10px;
  background-color: #f1f1f1;
}
</style>

Vue3中使用

TypeScript 复制代码
<template>
  <div>
    <!-- 内容部分 -->
    <div class="content">
      <div v-for="(item, index) in items" :key="index" class="item">
        {{ item }}
      </div>
    </div>

    <!-- 加载更多提示 -->
    <div id="loading" class="loading">加载更多...</div>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';

export default {
  setup() {
    const items = ref(['Item 1', 'Item 2', 'Item 3']); // 初始数据
    const page = ref(1); // 当前页数

    // 加载更多数据的函数
    const loadMoreData = () => {
      setTimeout(() => {
        const newItems = Array.from({ length: 5 }, (_, i) => `Item ${page.value * 5 + i + 1}`);
        items.value.push(...newItems); // 添加新数据
        page.value += 1; // 增加页码
      }, 1000); // 模拟网络请求延时
    };

    // 处理 IntersectionObserver 逻辑
    const handleIntersection = (entries, observer) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          loadMoreData(); // 如果加载更多区域进入视口,加载更多数据
        }
      });
    };

    // 在组件挂载时设置 IntersectionObserver
    onMounted(() => {
      const loadingElement = document.getElementById('loading');
      const observer = new IntersectionObserver(handleIntersection, {
        rootMargin: '0px',
        threshold: 1.0,
      });
      observer.observe(loadingElement);
    });

    return { items };
  },
};
</script>

<style>
.content {
  height: 1500px; /* 让页面滚动 */
}

.item {
  padding: 10px;
  margin: 10px 0;
  background-color: #f4f4f4;
  border: 1px solid #ddd;
}

.loading {
  text-align: center;
  padding: 10px;
  background-color: #f1f1f1;
}
</style>
相关推荐
过往记忆3 小时前
告别 Shuffle!深入探索 Spark 的 SPJ 技术
大数据·前端·分布式·ajax·spark
高兴蛋炒饭4 小时前
RouYi-Vue框架,环境搭建以及使用
前端·javascript·vue.js
m0_748240445 小时前
《通义千问AI落地—中》:前端实现
前端·人工智能·状态模式
ᥬ 小月亮5 小时前
Vue中接入萤石等直播视频(更新中ing)
前端·javascript·vue.js
夜斗(dou)5 小时前
node.js文件压缩包解析,反馈解析进度,解析后的文件字节正常
开发语言·javascript·node.js
恩爸编程6 小时前
纯 HTML+CSS+JS 实现一个炫酷的圣诞树动画特效
javascript·css·html·圣诞树·圣诞树特效·圣诞树js实现·纯js实现圣诞树
神雕杨6 小时前
node js 过滤空白行
开发语言·前端·javascript
网络安全-杰克6 小时前
《网络对抗》—— Web基础
前端·网络
m0_748250746 小时前
2020数字中国创新大赛-虎符网络安全赛道丨Web Writeup
前端·安全·web安全
周伯通*6 小时前
策略模式以及优化
java·前端·策略模式