Files
qiming/qiming-mobile/subpackages/pages/chat-conversation-component/layers/ScrollManager.uts

122 lines
4.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}