feat(chat-main-list): add collapsible sticky chat header on scroll

Add smooth transition animations for header height and content opacity. Handle scroll events to collapse the header when scrolling past the initial height, restore it when scrolled to top, and auto-collapse when sending a new chat message. Replace the static background image with a dynamic background div to support these transitions.
This commit is contained in:
duanshuwen
2026-06-29 14:32:18 +08:00
parent 02039a36e3
commit 14fbd3e50d

View File

@@ -9,10 +9,12 @@
class="min-h-0 flex-1 overflow-y-auto overscroll-contain scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden" class="min-h-0 flex-1 overflow-y-auto overscroll-contain scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
@scroll="handleScroll" @touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart" @scroll="handleScroll" @touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart"
@touchmove="handleScrollAreaTouchMove"> @touchmove="handleScrollAreaTouchMove">
<div class="relative"> <div class="relative transition-all duration-300 ease-in-out bg-cover bg-center bg-no-repeat"
<img class="w-full block" :src="mainPageDataModel?.initPageImages?.backgroundImageUrl" style="height: 252px" /> :class="{ 'sticky top-0 z-10': isHeaderCollapsed }"
:style="{ height: isHeaderCollapsed ? '50px' : '252px', backgroundImage: mainPageDataModel?.initPageImages?.backgroundImageUrl ? `url(${mainPageDataModel.initPageImages.backgroundImageUrl})` : 'none' }">
<div class="absolute bottom-0 left-0 right-0 flex-1"> <div class="absolute bottom-0 left-0 right-0 flex-1">
<div class="px-[12px] pt-[12px]"> <div class="px-[12px] pt-[12px] transition-all duration-300"
:class="{ 'opacity-0 max-h-0 overflow-hidden pt-0': isHeaderCollapsed }">
<Welcome :mainPageDataModel="mainPageDataModel" /> <Welcome :mainPageDataModel="mainPageDataModel" />
</div> </div>
<div style="margin-bottom: -1px"> <div style="margin-bottom: -1px">
@@ -348,7 +350,8 @@ const handleScrollAreaTouchMove = () => {
}; };
// 处理用户滚动事件 // 处理用户滚动事件
const welcomeHeight = ref(0); const welcomeHeight = ref(252);
const isHeaderCollapsed = ref(false);
let lastScrollTop = 0; let lastScrollTop = 0;
const handleScroll = (e) => { const handleScroll = (e) => {
if (Date.now() - lastScrollTouchAt < 1000) { if (Date.now() - lastScrollTouchAt < 1000) {
@@ -359,6 +362,17 @@ const handleScroll = (e) => {
e?.detail?.scrollTop ?? e?.target?.scrollTop ?? 0, e?.detail?.scrollTop ?? e?.target?.scrollTop ?? 0,
); );
const scrollEl = e?.target; const scrollEl = e?.target;
// 滚动回顶部时还原头部布局
if (currentScrollTop <= 0 && isHeaderCollapsed.value) {
isHeaderCollapsed.value = false;
}
// 向上滚动超过头部高度时收敛
if (currentScrollTop > welcomeHeight.value && !isHeaderCollapsed.value) {
isHeaderCollapsed.value = true;
}
if (topNavBarRef.value) { if (topNavBarRef.value) {
topNavBarRef.value.show = currentScrollTop > welcomeHeight.value; topNavBarRef.value.show = currentScrollTop > welcomeHeight.value;
} }
@@ -906,6 +920,9 @@ const sendMessage = async (message, isInstruct = false) => {
tabIndex.value = 1; tabIndex.value = 1;
} }
// 发起对话时收敛头部
isHeaderCollapsed.value = true;
// 检查WebSocket连接状态如果未连接尝试重新连接 // 检查WebSocket连接状态如果未连接尝试重新连接
if (!isWsConnected()) { if (!isWsConnected()) {
console.log("WebSocket未连接尝试重新连接..."); console.log("WebSocket未连接尝试重新连接...");