最近给公司官网开发了一个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对象具有一定的非实时性或者部分欺骗性?)


何弃疗
106 声望7 粉丝

前端路上摸爬滚打;野路子前端debug