useStickToBottom
设计时考虑了人工智能聊天机器人,为 StackBlitz 的bolt.new
提供支持
一个轻量级的零依赖 React hook + 组件,可自动粘贴到容器底部并平滑地对内容进行动画处理,以在添加新内容时保持其在屏幕上的视觉位置。
特征 不需要 Safari 不支持的overflow-anchor
浏览器级 CSS 支持。 可以使用带有 refs 的钩子连接到任何现有组件。或者简单地使用提供的组件,它为您处理引用并提供上下文 - 因此子组件可以检查isAtBottom
并以编程方式滚动到底部。 使用现代但受良好支持的ResizeObserver
API 来检测内容何时调整大小。 正确处理滚动锚定。这就是当视口上方的内容调整大小时,不会导致视口中当前显示的内容向上或向下跳跃。 允许用户通过向上滚动随时取消粘性。巧妙的逻辑将用户滚动与自定义动画滚动事件区分开来(不进行任何可能导致错过某些事件的去抖动)。 移动设备也可以很好地适应这种逻辑。 使用自定义实现的平滑滚动算法,具有基于速度的弹簧动画(具有可配置的参数)。其他库使用带有持续时间的缓动函数,但是当您想要以可变大小流式传输新内容时,这些函数效果不佳 - 这对于 AI 聊天机器人用例来说很常见。 scrollToBottom
返回一个Promise
一旦滚动成功,它将解析为true
,如果滚动被取消,则解析为false
。
用法
组件
{messages.map((message) => (
))}
{/* This component uses `useStickToBottomContext` to scroll to bottom when the user enters a message */}
);
}
function ScrollToBottom() {
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
return (
!isAtBottom && (
scrollToBottom()}
/>
)
);
}"> import { StickToBottom , useStickToBottomContext } from 'use-stick-to-bottom' ;
function Chat ( ) {
return (
< StickToBottom className = "h-[50vh] relative" resize = "smooth" initial = "smooth" >
< StickToBottom . Content className = "flex flex-col gap-4" >
{ messages . map ( ( message ) => (
< Message key = { message . id } message = { message } / >
) ) }
< / StickToBottom . Content >
< ScrollToBottom / >
{ /* This component uses `useStickToBottomContext` to scroll to bottom when the user enters a message */ }
< ChatBox / >
< / StickToBottom >
) ;
}
function ScrollToBottom ( ) {
const { isAtBottom , scrollToBottom } = useStickToBottomContext ( ) ;
return (
! isAtBottom && (
< button
className = "absolute i-ph-arrow-circle-down-fill text-4xl rounded-lg left-[50%] translate-x-[-50%] bottom-0"
onClick = { ( ) => scrollToBottom ( ) }
/ >
)
) ;
}
useStickToBottom
钩子 import { useStickToBottom } from 'use-stick-to-bottom' ;
function Component ( ) {
const { scrollRef , contentRef } = useStickToBottom ( ) ;
return (
< div style = { { overflow : 'auto' } } ref = { scrollRef } >
< div ref = { contentRef } >
{ messages . map ( ( message ) => (
< Message key = { message . id } message = { message } / >
) ) }
< / div >
< / div >
) ;
}