流程梳理
image.png
流程中的操作有三类。
- 页面自动滑动
- 用户手动滑动
- 点击按钮滑到底部
import { useState, useEffect, useRef } from 'react';
import toDown from '@/images/toDown.svg';
export default function DropFun() {
// 显示内容 dom
const chatContainerRef = useRef<any>(null);
// 流式输出内容
const [chatList, chatList] = useState<any[]>([]);
// 是否显示 滑到底部 按钮
const [dropDisplay, setDropDisplay] = useState(false);
// 可视区域滚动到底部
const dropDown = () => {
const containerHeight = chatContainerRef.current.scrollHeight;
setTimeout(() => {
chatContainerRef.current.scrollTop = containerHeight;
}, 0)
}
// 对话发起请求,流式返回数据
const handleSend = () => {
setAutoDrop(true);
//...
}
// 每次渲染页面高度的变化后,监听滚动的变化
useEffect(() => {
if (chatContainerRef) {
const viewHeight = document.documentElement.clientHeight || document.body.clientHeight;
chatchatContainerRef.current.addEventListener('scroll', (e: any) => {
const curHeight = e.target.scrollHeight - e.target.scrollTop;
// 当本次距离顶部距离小于上次距离顶部距离,则可判断用户在向上滑动,停止页面自动滑动
if (e.target.scrollTop <= lastScrollTop) {
setAutoDrop(false);
}
// 记录上一次滑动距顶部距离
lastScrollTop = e.target.scrollTop;
// 当页面高度大于窗口可视区域高度,就可以展示置顶按钮
if (e.target.scrollTop >= 0 && curHeight > viewHeight) {
setDropDisplay(true);
} else {
setDropDisplay(false);
}
// 当可视区域底部到页面内容底部小于 200px 时触发页面自动滑动
if (e.target.scrollTop >= 0 && curHeight <= viewHeight + 200) {
setAutoDrop(true);
}
})
}
}, [chatContainerRef, chatList])
// 流式输出内容时,触发页面滚动判断
useEffect(() => {
if (autoDrop) dropDown();
}, [chatList])
return (
<>
<div ref={chatContainerRef}>
{chatList.map(item) => {
// 渲染对话内容
}}
</div>
{dropDisplay && <img src={toDown.src} onClick={dropDown} />}
</>
)
}