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>