* 智能滚动到底部 * @param {boolean} force - 是否强制滚动
(force = false)
| 84 | * @param {boolean} force - 是否强制滚动 |
| 85 | */ |
| 86 | async scrollToBottom(force = false) { |
| 87 | await nextTick() |
| 88 | // 等待 DOM 布局稳定 |
| 89 | await this.waitForLayoutStable() |
| 90 | |
| 91 | // 只有在应该自动滚动时才执行(除非强制) |
| 92 | if (!force && !this.shouldAutoScroll) return |
| 93 | |
| 94 | const container = this.getContainer() |
| 95 | if (!container) return |
| 96 | |
| 97 | // 标记为程序性滚动 |
| 98 | this.isProgrammaticScroll = true |
| 99 | |
| 100 | // 记录滚动前的容器高度 |
| 101 | const initialHeight = container.scrollHeight |
| 102 | |
| 103 | const scrollOptions = { |
| 104 | top: container.scrollHeight, |
| 105 | behavior: 'smooth' |
| 106 | } |
| 107 | |
| 108 | // 立即滚动 |
| 109 | container.scrollTo(scrollOptions) |
| 110 | |
| 111 | // 多次重试确保滚动成功,包括等待输入框等动态元素布局完成 |
| 112 | const retryDelays = [50, 100, 200, 400] |
| 113 | retryDelays.forEach((delay, index) => { |
| 114 | setTimeout(() => { |
| 115 | if (force || this.shouldAutoScroll) { |
| 116 | this.isProgrammaticScroll = true |
| 117 | const behavior = index === retryDelays.length - 1 ? 'auto' : 'smooth' |
| 118 | |
| 119 | // 如果高度变化了,说明可能有动态内容正在渲染,再次等待 |
| 120 | if (container.scrollHeight !== initialHeight && index < retryDelays.length - 1) { |
| 121 | this.waitForLayoutStable().then(() => { |
| 122 | container.scrollTo({ |
| 123 | top: container.scrollHeight, |
| 124 | behavior |
| 125 | }) |
| 126 | }) |
| 127 | } else { |
| 128 | container.scrollTo({ |
| 129 | top: container.scrollHeight, |
| 130 | behavior |
| 131 | }) |
| 132 | } |
| 133 | } |
| 134 | }, delay) |
| 135 | }) |
| 136 | } |
| 137 | |
| 138 | async scrollToBottomStaticForce() { |
| 139 | const container = this.getContainer() |
nothing calls this directly
no test coverage detected