feat: 兼容在app上页面滚动与键盘问题

This commit is contained in:
2026-05-11 15:54:28 +08:00
parent 85a61d5bbf
commit 9cd3916ab2
6 changed files with 149 additions and 36 deletions

View File

@@ -15,6 +15,6 @@
</head> </head>
<body> <body>
<div id="app"><!--app-html--></div> <div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script> <script type="module" src="/src/main.js"></script>
</body> </body>
</html> </html>

View File

@@ -3,7 +3,12 @@
{ {
"path": "pages/index/index", "path": "pages/index/index",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom",
"disableScroll": true,
"app-plus": {
"bounce": "none",
"scrollIndicator": "none"
}
} }
}, },
{ {

View File

@@ -33,6 +33,7 @@
confirm-type="send" confirm-type="send"
v-model="inputMessage" v-model="inputMessage"
auto-height auto-height
:focus="isFocused"
:confirm-hold="true" :confirm-hold="true"
:placeholder="placeholder" :placeholder="placeholder"
:show-confirm-bar="false" :show-confirm-bar="false"
@@ -322,20 +323,28 @@ const handleTouchEnd = () => {
// 手动聚焦输入框 // 手动聚焦输入框
const focusInput = () => { const focusInput = () => {
if (textareaRef.value) { isFocused.value = true;
textareaRef.value.focus(); nextTick(() => {
} if (textareaRef.value) {
textareaRef.value.focus();
}
});
}; };
// 手动失焦输入框 // 手动失焦输入框
const blurInput = () => { const blurInput = () => {
isFocused.value = false;
if (textareaRef.value) { if (textareaRef.value) {
textareaRef.value.blur(); textareaRef.value.blur();
} }
nextTick(() => {
uni.hideKeyboard();
});
}; };
// 暴露方法给父组件 // 暴露方法给父组件
defineExpose({ focusInput }); defineExpose({ focusInput, blurInput });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,5 +1,5 @@
<template> <template>
<view class="flex flex-col h-screen relative"> <view class="flex flex-col h-screen relative overflow-hidden">
<!-- 顶部自定义导航栏 --> <!-- 顶部自定义导航栏 -->
<view class="header absolute top-0 left-0 w-full z-10" :style="{ paddingTop: statusBarHeight + 'px' }"> <view class="header absolute top-0 left-0 w-full z-10" :style="{ paddingTop: statusBarHeight + 'px' }">
<ChatTopNavBar <ChatTopNavBar
@@ -21,19 +21,31 @@
</view> </view>
</view> </view>
<view v-show="tabIndex === 0" class="flex-full overflow-hidden scroll-y"> <view
<Discovery /> v-show="tabIndex === 0"
class="main-scroll-area flex-full overflow-hidden min-height-0"
@touchstart.capture="handleScrollAreaTouchStart"
@touchstart="handleScrollAreaTouchStart"
@touchmove="handleScrollAreaTouchMove"
>
<Discovery
@scroll-touch-start="handleScrollAreaTouchStart"
@scroll-touch="handleScrollAreaTouchMove"
/>
</view> </view>
<!-- 消息列表可滚动区域 --> <!-- 消息列表可滚动区域 -->
<scroll-view <scroll-view
v-show="tabIndex === 1" v-show="tabIndex === 1"
class="main flex-full overflow-hidden scroll-y" class="main main-scroll-area flex-full overflow-hidden min-height-0"
scroll-y scroll-y
:scroll-top="scrollTop" :scroll-top="scrollTop"
:scroll-with-animation="true" :scroll-with-animation="true"
@scroll="handleScroll" @scroll="handleScroll"
@scrolltolower="handleScrollToLower" @scrolltolower="handleScrollToLower"
@touchstart.capture="handleScrollAreaTouchStart"
@touchstart="handleScrollAreaTouchStart"
@touchmove="handleScrollAreaTouchMove"
> >
<view <view
@@ -195,7 +207,7 @@
<script setup> <script setup>
import { onMounted, nextTick, onUnmounted, ref } from "vue"; import { onMounted, nextTick, onUnmounted, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad, onReady } from "@dcloudio/uni-app";
import { import {
SWITCH_TO_COMPANION_TAB, SWITCH_TO_COMPANION_TAB,
SWITCH_TO_DISCOVERY_TAB, SWITCH_TO_DISCOVERY_TAB,
@@ -271,6 +283,8 @@ const inputMessage = ref("");
/// 是否自动滚动到底部 (人工手动向上滚动时设为false) /// 是否自动滚动到底部 (人工手动向上滚动时设为false)
const isAutoScroll = ref(true); const isAutoScroll = ref(true);
let lastHideKeyboardAt = 0;
let lastScrollTouchAt = 0;
/// agentId 首页接口中获取 /// agentId 首页接口中获取
const agentId = ref("1"); const agentId = ref("1");
@@ -348,10 +362,46 @@ const handleKeyboardHide = () => {
holdKeyboard.value = false; holdKeyboard.value = false;
}; };
const hideKeyboardByScroll = () => {
const now = Date.now();
if (now - lastHideKeyboardAt < 300) return;
lastHideKeyboardAt = now;
holdKeyboard.value = false;
holdKeyboardFlag.value = true;
isKeyboardShow.value = false;
if (inputAreaRef.value && inputAreaRef.value.blurInput) {
inputAreaRef.value.blurInput();
}
uni.hideKeyboard();
// #ifdef APP-PLUS
if (typeof plus !== "undefined" && plus.key && plus.key.hideSoftKeybord) {
plus.key.hideSoftKeybord();
}
// #endif
};
const handleScrollAreaTouchStart = () => {
lastScrollTouchAt = Date.now();
hideKeyboardByScroll();
};
const handleScrollAreaTouchMove = () => {
lastScrollTouchAt = Date.now();
hideKeyboardByScroll();
};
// 处理用户滚动事件 // 处理用户滚动事件
const welcomeHeight = ref(0); const welcomeHeight = ref(0);
let lastScrollTop = 0; let lastScrollTop = 0;
const handleScroll = (e) => { const handleScroll = (e) => {
if (Date.now() - lastScrollTouchAt < 1000) {
hideKeyboardByScroll();
}
const detail = e.detail; const detail = e.detail;
topNavBarRef.value.show = parseInt(detail.scrollTop) > welcomeHeight.value; topNavBarRef.value.show = parseInt(detail.scrollTop) > welcomeHeight.value;
@@ -484,6 +534,21 @@ onLoad(() => {
}); });
}); });
onReady(() => {
// #ifdef APP-PLUS
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentWebview = currentPage && currentPage.$getAppWebview && currentPage.$getAppWebview();
if (currentWebview && currentWebview.setStyle) {
currentWebview.setStyle({
bounce: "none",
scrollIndicator: "none",
});
}
// #endif
});
// token存在初始化数据 // token存在初始化数据
const initHandler = () => { const initHandler = () => {
console.log("initHandler"); console.log("initHandler");
@@ -1229,4 +1294,11 @@ const resetConfig = () => {
}; };
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped>
.main-scroll-area {
flex-basis: 0;
height: 0;
min-height: 0;
overscroll-behavior-y: contain;
}
</style>

View File

@@ -9,7 +9,14 @@
/> />
</view> </view>
<scroll-view class="flex-full border-box min-height-0" scroll-y show-scrollbar="false"> <scroll-view
class="discovery-scroll flex-full border-box min-height-0"
scroll-y
show-scrollbar="false"
@touchstart="emitScrollTouchStart"
@touchmove="emitScrollTouch"
@scroll="emitScrollTouch"
>
<CardSwiper v-if="discoveryCards.length > 0" :list="discoveryCards" @didSelectItem="handleCardClick" /> <CardSwiper v-if="discoveryCards.length > 0" :list="discoveryCards" @didSelectItem="handleCardClick" />
<QuickQuestions v-if="discoveryQuickQuestions.length > 0" :list="discoveryQuickQuestions" @didSelectItem="handleQuickQuestionClick" /> <QuickQuestions v-if="discoveryQuickQuestions.length > 0" :list="discoveryQuickQuestions" @didSelectItem="handleQuickQuestionClick" />
@@ -42,6 +49,15 @@ const activeIndex = ref(0);
const discoveryTabs = ref([]); const discoveryTabs = ref([]);
const discoveryCards = ref([]); const discoveryCards = ref([]);
const discoveryQuickQuestions = ref([]); const discoveryQuickQuestions = ref([]);
const emit = defineEmits(["scroll-touch-start", "scroll-touch"]);
const emitScrollTouchStart = () => {
emit("scroll-touch-start");
};
const emitScrollTouch = () => {
emit("scroll-touch");
};
/// tabs 切换事件 /// tabs 切换事件
const handleTabChange = ({ tab, idx }) => { const handleTabChange = ({ tab, idx }) => {
@@ -188,5 +204,10 @@ onMounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.discovery-scroll {
flex-basis: 0;
height: 0;
min-height: 0;
overscroll-behavior-y: contain;
}
</style> </style>

View File

@@ -1,22 +1,22 @@
<template> <template>
<view class="w-full h-screen bg-liner"> <view class="index-page w-full h-screen overflow-hidden bg-liner">
<ChatMainList /> <ChatMainList />
<!-- 日历组件 -->
<Calender
:visible="calendarVisible"
mode="single"
:default-value="selectedDate"
@close="handleCalendarClose"
@select="handleDateSelect"
/>
<!-- 更多服务 -->
<MoreService />
<!-- 抽屉组件 -->
<DrawerSection ref="drawerRef" @close="closeDrawer" />
</view> </view>
<!-- 日历组件 -->
<Calender
:visible="calendarVisible"
mode="single"
:default-value="selectedDate"
@close="handleCalendarClose"
@select="handleDateSelect"
/>
<!-- 更多服务 -->
<MoreService />
<!-- 抽屉组件 -->
<DrawerSection ref="drawerRef" @close="closeDrawer" />
</template> </template>
<script setup> <script setup>
@@ -88,6 +88,12 @@ onUnmounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.index-page {
position: relative;
min-height: 0;
overscroll-behavior: none;
}
.top { .top {
margin-top: 150px; margin-top: 150px;
} }