# 大模型输出的文本展示到页面上并实现自动滚动

思路:只需要在拼接字符的时候调用scrollIntoView或scrollTo就可以了

使用scrollIntoView()让页面滚动,使目标元素进入可视区域

const scrollThrottle = ref(false)
const scrollToLatestMessage = () => {
  const sessionEm = conversationRef.value
  if (sessionEm) {
    if (scrollThrottle.value) return
    scrollThrottle.value = true

    requestAnimationFrame(() => {
      conversationRef.value?.scrollIntoView({ behavior: 'smooth', block: 'end' })
      setTimeout(() => {
        scrollThrottle.value = false
      }, 100)
    })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  1. 这里添加了Throttle节流控制,避免短时间内多次触发滚动操作

  2. 使用 requestAnimationFrame:将滚动操作放在 requestAnimationFrame 回调中执行,可以确保在浏览器的下一帧渲染时进行滚动,提高性能和流畅度。

属性 说明 常用值
behavior 滚动动画行为 'auto'(默认) or 'smooth'
block 垂直方向对齐方式 'start'(顶部)、'end'(底部)、'nearest'
inline 水平方向对齐方式 通常不需要设,除非横向滚动
element.scrollIntoView({
  behavior: 'smooth',
  block: 'end'
})
1
2
3
4

这个写法会平滑地滚动,让元素出现在容器的底部。

# 如何区分用户滚动和代码滚动

给需要滚动的容器的父元素添加一个wheel事件,使用鼠标滚轮滚动时就会触发这个wheel事件,然后通过响应式状态来判断

const conversationRef = useTemplateRef('conversationRef')
const scrollContainerRef = useTemplateRef('scrollContainerRef')
const userScrolled = ref(false)
const scrollThrottle = ref(false)
const scrollToLatestMessage = () => {
  const sessionEm = conversationRef.value
  if (sessionEm) {
    if (scrollThrottle.value || userScrolled.value) return // 如果用户手动滚动,则不再自动滚动
    scrollThrottle.value = true

    requestAnimationFrame(() => {
      conversationRef.value?.scrollIntoView({ behavior: 'smooth', block: 'end' })
      setTimeout(() => {
        scrollThrottle.value = false
      }, 100)
    })
  }
}

onMounted(() => {
  if (scrollContainerRef.value) {
    scrollContainerRef.value.addEventListener(
      'wheel',
      debounce(() => {
        console.log('用户滚动了')
        userScrolled.value = true
      }, 100)
    )
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30