【发布时间】:2022-11-18 11:38:06
【问题描述】:
我正在无限向上滚动聊天室,判断看到最后一条消息并加载数据,但是滚动条仍然在页面顶部,你知道的,它会自动无限执行调用api,如何保持该位置上一条消息的滚动条
【问题讨论】:
标签: javascript html css reactjs infinite-scroll
我正在无限向上滚动聊天室,判断看到最后一条消息并加载数据,但是滚动条仍然在页面顶部,你知道的,它会自动无限执行调用api,如何保持该位置上一条消息的滚动条
【问题讨论】:
标签: javascript html css reactjs infinite-scroll
如果您有添加的新元素的引用,您可以使用 element.scrollIntoView() 来确保它在渲染后可见。
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
但: 在聊天室中,这可能并不总是正确的做法,因为用户可能已经向上滚动以复制/粘贴某些内容,而失去位置会很烦人。因此,在通过 JS 滚动之前,请检查聊天是否已经在底部。
您可以查看 twitch-chat 的工作原理以获得一个很好的示例。如果有新的聊天消息,用户会收到一条信息。
【讨论】:
此解决方案适用于图书馆 https://github.com/ankeetmaini/react-infinite-scroll-component
我使用的结构基于传递给子组件的道具。父组件负责获取和控制状态。
父组件:
const fetchScrollData = () => {
// Here we set that we are not able to do scrolling fetching
setIsLoadingScrollData(true);
// Apply here some pagination calculation
searchData()
.then((tempData) => {
// Here i am saving the id of the first message
// I had before scrolling
setShouldScrollToId(data[0].id);
const newData = tempData.concat(data);
setData(newData);
// Apply here some logic, depending if you have finished or not
setHasMoreData(true);
})
.then(() => {
setTimeout(() => {
// Change the timeout accordingly
// hack for setting the isloading to false when everything is done
setIsLoadingScrollData(false);
}, 1500);
});
};
子组件
type PropsType = {
fetchScrollData: () => void;
hasMoreData: boolean;
data: string[];
isLoadingScrollData: boolean;
shouldScrollToId: string;
};
const ChildComponent: FC<PropsType> = (props: PropsType) => {
useEffect(() => {
if (props.shouldScrollToId !== '') {
const element = document.getElementById(props.shouldScrollToId);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
}
});
....
return (
<div
className="message-list overflow-scroll"
id="scrollableDiv"
style={{
display: 'flex',
flexDirection: 'column-reverse'
}}>
<InfiniteScroll
dataLength={props.data.length}
hasMore={props.hasMoreData && !props.isLoadingScrollData}
inverse={true}
next={props.fetchScrollData}
scrollableTarget="scrollableDiv"
style={{ display: 'flex', flexDirection: 'column-reverse', perspective: '1px' }}
loader={<></>}>
<div>
{props.data.map((d, index) => {
// Here i am setting the id which the useEffect will use to do the scroll
<div key={index} id={d.id} >div - #{message}</div>;
})}
</div>
{props.isLoadingScrollData ? <Spinner></Spinner> : null}
</InfiniteScroll>
</div>
我在加载器上遇到了一些问题,所以我决定不使用它。相反,我创建了自己的 Spinner 组件,并根据显示我们是否仍在从滚动中获取数据的道具使其出现或消失。
【讨论】: