import { nextTick } from "vue"; import AgentDetailData from "./AgentDetailData.uts"; /** * 滚动管理层:专门处理滚动相关的逻辑 * 兼容微信小程序和 H5/App */ export default class ScrollManager { private data: AgentDetailData; // 记录上次滚动位置,用于判断滚动方向 private lastScrollTop: number = 0; constructor(private data: AgentDetailData) { this.data = data; } /** * 滚动到最后一条消息 * 使用 scroll-into-view 方式,兼容所有平台 */ scrollToLastMsg(userClick: boolean): void { this.data.autoToLastMsg.value = true; this.data.scrollIntoView.value = ""; this.data.scrollWithAnimation.value = userClick; nextTick(() => { this.data.scrollIntoView.value = "last-msg"; this.data.scrollInBottom.value = true; }); } /** * 设置是否在滚动底部 * 使用 scroll 事件参数,兼容微信小程序 */ setIsInScrollBottom(e: UniScrollEvent): void { nextTick(() => { // 使用事件参数获取滚动信息,兼容微信小程序 const scrollTop = e?.detail?.scrollTop ?? 0; const scrollHeight = e?.detail?.scrollHeight ?? 0; // #ifdef MP-WEIXIN // 微信小程序需要通过其他方式获取容器高度,这里使用估算值 const offsetHeight = 600; // 默认视窗高度估算 // #endif // #ifndef MP-WEIXIN const scrollList = uni.getElementById("msg-list"); const offsetHeight = scrollList?.offsetHeight ?? 600; // #endif const diff: number = scrollHeight - scrollTop - offsetHeight; const isInBottom = diff < 50; this.data.scrollInBottom.value = isInBottom; // 如果滑到底部,自动恢复自动滚动 if (isInBottom) { this.data.autoToLastMsg.value = true; } // 只有在用户主动滚动(触摸或鼠标)时才可能禁用自动滚动 // 且只在向上滚动(远离底部)时禁用 const isScrollingUp = scrollTop < this.lastScrollTop; this.lastScrollTop = scrollTop; if ( (this.data.scrollTouch.value || this.data.mouseScroll.value) && isScrollingUp && !isInBottom ) { // 用户向上滚动时,立即禁用自动滚动,不需要等待滚动到一定距离 // 这样用户可以更容易地中断快速消息流带来的自动滚动 this.data.autoToLastMsg.value = false; // 同时显示"滚动到底部"按钮 this.data.scrollInBottom.value = false; } }); } /** * 锁定自动滚动到底部 * 修复:不再过早禁用自动滚动,仅在特殊情况下处理 */ lockAutoToLastMsg(): void { // 如果已经处理过或不需要锁定,直接返回 if (!this.data.needSetLockAutoToLastMsg.value) return; // 简化逻辑:只有当消息列表为空时才禁用 // 其他情况保持 autoToLastMsg 的当前状态 if (this.data.messageList.value.length === 0) { this.data.autoToLastMsg.value = false; this.data.needSetLockAutoToLastMsg.value = false; } } /** * 滚动事件处理 * 修复:不再错误地设置 mouseScroll,让触摸和鼠标滚动分开处理 */ onScroll(e: UniScrollEvent): void { // mouseScroll 只在 H5 平台由 wheel 事件设置,这里不设置 // 触摸滚动由 touchstart/touchend 事件控制 scrollTouch this.setIsInScrollBottom(e); this.data.scrolling.value = true; if (this.data.scrollingT.value != 0) { clearTimeout(this.data.scrollingT.value); } this.data.scrollingT.value = setTimeout(() => { this.data.scrolling.value = false; }, 500); } /** * 滚动到指定消息位置 * 用于加载更多历史消息后保持滚动位置 */ scrollToMessage(messageId: string | number): void { this.data.scrollWithAnimation.value = false; this.data.scrollIntoView.value = ""; // 延迟设置,确保微信小程序 DOM 渲染完成后再触发定位 setTimeout(() => { this.data.scrollIntoView.value = `msg-wrapper-${messageId}`; }, 150); } }