import React, { useRef, useEffect, useState } from 'react';
import Item from './item';
import styles from './index.module.less';
const Home = () => {
const [itemsObj, setItemObj] = useState({});
const [prevScrollTop, setPrevScrollTop] = useState(0);
const [data, setData] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
const homeRef = useRef(null);
const computedItems = () => {
const homeRect = homeRef.current.getBoundingClientRect();
const items = document.getElementsByName('item');
items.forEach((item) => {
const itemRect = item.getBoundingClientRect();
itemsObj[item.id] = { ...(itemsObj[item.id] || {}), itemRect };
// 距离底部20px就加载
itemsObj[item.id].intoViewport = itemsObj[item.id].intoViewport
|| (itemRect.top - homeRect.top) < homeRect.height + 20;
});
setItemObj({ ...itemsObj });
};
useEffect(() => {
computedItems();
}, []);
return (
<div
ref={homeRef}
className={styles.home}
onScroll={() => {
window.clearTimeout(homeRef.current.watchTimer);
homeRef.current.watchTimer = setTimeout(() => {
const { current } = homeRef;
const direction = current.scrollTop - prevScrollTop > 0 ? 'down' : 'up';
// 向下滚动到离底部一段距离时,而且是第一次,就加载数据,
// 这里通过prevScrollTop + current.clientHeight + 30 > current.scrollHeight来判断是否第一次
const bottomDis = 50;
const isReachedBottom = prevScrollTop + current.clientHeight
+ bottomDis > current.scrollHeight;
if (direction === 'down'
&& !isReachedBottom
&& current.scrollTop + current.clientHeight + bottomDis > current.scrollHeight) {
const len = data.length;
for (let i = len + 1; i < len + 10; i += 1) {
data.push(i);
}
setData([...data]);
}
setPrevScrollTop(current.scrollTop);
computedItems();
}, 50);
}}
>
{
data.map((i) => (
<Item
key={i}
rect={itemsObj[i] || {}}
i={i}
/>
))
}
</div>
);
};
export default Home;
import React from 'react';
import styles from './index.module.less';
export default class Item extends React.Component {
render() {
const { i, rect } = this.props;
return (
<div
className={styles.item}
name="item"
id={i}
>
<div>{i}</div>
{ rect.intoViewport ? '出现了' : '隐藏了'}
</div>
);
}
}
.home{
flex: 1;
margin: 12px;
overflow: auto;
}
.item{
position: relative;
background: white;
margin-bottom: 12px;
height: 100px;
border-radius: 8px;
border: 1px solid #D9D9D9;
&:after{
position: absolute;
content: '';
bottom: 0;
height: 8px;
left: 0;
right: 0;
background: red;
}
}