最近给公司官网开发了一个AI会话客服功能,通过输入信息,调用大模型接口,流式返回数据,增量更新内容,随着内容变多,保持窗口滚动到底部。
滚动时机
原生的HTML操作是在dom上直接修改数据,或者追加节点,追加完之后即可执行滚动操作,而Vue或者其他框架则不同,由于使用虚拟dom,采用数据驱动模式,多段会话即一个list集合控制,且当前正在会话的数据对象是一直变化的。由于数据的更新是异步的,所以在数据更新后,立即执行滚动是不妥的,真实的情况是必须在dom完成更新后,它的内部高度撑起来,再去执行e.scrollTop = e.scrollHeight
,这个时机不同的框架有不同的处理方案,Vue通常为nextTick()
,React setData 方法有回调,还有冷门的ReactDom.flushSync
,在这个方法执行所需的数据更新,Angular有ChangeDetectorRef
,在构造器中注入实例对象,通用的方法为setTimeout
。
scrollTop 不生效
有了稳定的时机,之后直接进行dom操作即可,按照惯例,事先挂载一个ref对元素的引用,执行代码chatWindow.value.scrollTop = chatWindow.value.Height
,执行了,但是无效,通过打印日志,Height,也是具有真实数值的,引用对象没错,还是说ref获取的dom实例,不具有实时性?问过AI,表明ref是具有实时更新的特性的,不然获取高度就出错了,如果有人知道,评论区指导,非常感谢。
解决方案
采用了原生获取dom对象的方式,每次发送完消息后,立即获取dom对象并且赋值给ref,chatWindow.value = document.getElementById('chat-window')
,之后使用chatWindow.value.scrollTop = chatWindow.value.Height
,则可以正常滚动到窗口底部,保证用户看到的都是最新的回复消息。(到这里是否页已经证明了,ref引用dom对象具有一定的非实时性或者部分欺骗性?)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。