react中用法
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(() => {// 创建 IntersectionObserverconst observer = new IntersectionObserver(([entry]) => {if (entry.isIntersecting) {loadMoreData(); // 当加载元素进入视口时,触发加载更多数据}},{rootMargin: '0px', // 可根据需要调整,决定何时触发threshold: 1.0, // 触发条件:元素完全进入视口});// 启动观察if (loaderRef.current) {observer.observe(loaderRef.current);}// 清理 observerreturn () => {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中用法
<!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 // 完全进入视口时触发});// 启动 IntersectionObserverobserver.observe(loadingElement);</script>
</body>
</html>
Vue2中使用
<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中使用
<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(); // 如果加载更多区域进入视口,加载更多数据}});};// 在组件挂载时设置 IntersectionObserveronMounted(() => {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>