feat:修复键盘的问题
This commit is contained in:
11
pages.json
11
pages.json
@@ -13,6 +13,17 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/chat/ChatMainList",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"app-plus": {
|
||||||
|
"softinputMode": "adjustPan",
|
||||||
|
"bounce": "none",
|
||||||
|
"titleNView": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/chat/ChatQuickAccess",
|
"path": "pages/chat/ChatQuickAccess",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- 输入框 -->
|
<!-- 输入框 -->
|
||||||
<textarea
|
<textarea
|
||||||
|
ref="textareaRef"
|
||||||
class="textarea"
|
class="textarea"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@@ -13,11 +14,15 @@
|
|||||||
confirm-type='done'
|
confirm-type='done'
|
||||||
v-model="inputMessage"
|
v-model="inputMessage"
|
||||||
@confirm="sendMessage"
|
@confirm="sendMessage"
|
||||||
@touchend="handleNoHideKeyboard"
|
@focus="handleFocus"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@touchstart="handleTouchStart"
|
||||||
|
@touchend="handleTouchEnd"
|
||||||
:confirm-hold="true"
|
:confirm-hold="true"
|
||||||
auto-height
|
auto-height
|
||||||
:show-confirm-bar='false'
|
:show-confirm-bar='false'
|
||||||
:hold-keyboard="holdKeyboard"
|
:hold-keyboard="holdKeyboard"
|
||||||
|
:adjust-position="true"
|
||||||
maxlength="300"
|
maxlength="300"
|
||||||
/>
|
/>
|
||||||
<view class="input-container-send" @click="sendMessage">
|
<view class="input-container-send" @click="sendMessage">
|
||||||
@@ -27,33 +32,90 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
inputMessage: String,
|
inputMessage: String,
|
||||||
holdKeyboard: Boolean
|
holdKeyboard: Boolean
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['update:inputMessage', 'send', 'noHideKeyboard'])
|
const emit = defineEmits(['update:inputMessage', 'send', 'noHideKeyboard', 'keyboardShow', 'keyboardHide'])
|
||||||
|
|
||||||
|
const textareaRef = ref(null)
|
||||||
const placeholder = ref('快告诉朵朵您在想什么~')
|
const placeholder = ref('快告诉朵朵您在想什么~')
|
||||||
const inputMessage = ref(props.inputMessage || '')
|
const inputMessage = ref(props.inputMessage || '')
|
||||||
|
const isFocused = ref(false)
|
||||||
|
const keyboardHeight = ref(0)
|
||||||
|
|
||||||
// 保持和父组件同步
|
// 保持和父组件同步
|
||||||
watch(() => props.inputMessage, (val) => {
|
watch(() => props.inputMessage, (val) => {
|
||||||
inputMessage.value = val
|
inputMessage.value = val
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 监听键盘高度变化
|
||||||
|
onMounted(() => {
|
||||||
|
// 监听键盘弹起
|
||||||
|
uni.onKeyboardHeightChange((res) => {
|
||||||
|
keyboardHeight.value = res.height
|
||||||
|
if (res.height > 0) {
|
||||||
|
emit('keyboardShow', res.height)
|
||||||
|
} else {
|
||||||
|
emit('keyboardHide')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const sendMessage = () => {
|
const sendMessage = () => {
|
||||||
if (!inputMessage.value.trim()) return;
|
if (!inputMessage.value.trim()) return;
|
||||||
emit('send', inputMessage.value)
|
emit('send', inputMessage.value)
|
||||||
inputMessage.value = ''
|
inputMessage.value = ''
|
||||||
emit('update:inputMessage', inputMessage.value)
|
emit('update:inputMessage', inputMessage.value)
|
||||||
|
|
||||||
|
// 发送后保持焦点(可选)
|
||||||
|
if (props.holdKeyboard && textareaRef.value) {
|
||||||
|
nextTick(() => {
|
||||||
|
textareaRef.value.focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleNoHideKeyboard = () => {
|
const handleFocus = () => {
|
||||||
|
isFocused.value = true
|
||||||
emit('noHideKeyboard')
|
emit('noHideKeyboard')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleBlur = () => {
|
||||||
|
isFocused.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTouchStart = () => {
|
||||||
|
emit('noHideKeyboard')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTouchEnd = () => {
|
||||||
|
emit('noHideKeyboard')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动聚焦输入框
|
||||||
|
const focusInput = () => {
|
||||||
|
if (textareaRef.value) {
|
||||||
|
textareaRef.value.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动失焦输入框
|
||||||
|
const blurInput = () => {
|
||||||
|
if (textareaRef.value) {
|
||||||
|
textareaRef.value.blur()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
focusInput,
|
||||||
|
blurInput,
|
||||||
|
isFocused
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -64,6 +126,8 @@ const handleNoHideKeyboard = () => {
|
|||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
box-shadow: 0px 0px 20px 0px rgba(52,25,204,0.05);
|
box-shadow: 0px 0px 20px 0px rgba(52,25,204,0.05);
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
|
/* 确保输入框在安全区域内 */
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
.input-container-voice {
|
.input-container-voice {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -61,10 +61,13 @@
|
|||||||
<view class="footer-area">
|
<view class="footer-area">
|
||||||
<ChatQuickAccess @replySent="handleReplyInstruct"/>
|
<ChatQuickAccess @replySent="handleReplyInstruct"/>
|
||||||
<ChatInputArea
|
<ChatInputArea
|
||||||
|
ref="inputAreaRef"
|
||||||
v-model="inputMessage"
|
v-model="inputMessage"
|
||||||
:holdKeyboard="holdKeyboard"
|
:holdKeyboard="holdKeyboard"
|
||||||
@send="sendMessageAction"
|
@send="sendMessageAction"
|
||||||
@noHideKeyboard="handleNoHideKeyboard"
|
@noHideKeyboard="handleNoHideKeyboard"
|
||||||
|
@keyboardShow="handleKeyboardShow"
|
||||||
|
@keyboardHide="handleKeyboardHide"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -72,7 +75,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup >
|
<script setup >
|
||||||
import { onMounted, nextTick } from 'vue'
|
import { onMounted, nextTick, computed } from 'vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { defineEmits } from 'vue'
|
import { defineEmits } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app';
|
import { onLoad } from '@dcloudio/uni-app';
|
||||||
@@ -106,12 +109,18 @@
|
|||||||
|
|
||||||
/// 导航栏相关
|
/// 导航栏相关
|
||||||
const statusBarHeight = ref(20);
|
const statusBarHeight = ref(20);
|
||||||
|
/// 输入框组件引用
|
||||||
|
const inputAreaRef = ref(null);
|
||||||
|
|
||||||
const timer = ref(null)
|
const timer = ref(null)
|
||||||
/// focus时,点击页面的时候不收起键盘
|
/// focus时,点击页面的时候不收起键盘
|
||||||
const holdKeyboard = ref(false)
|
const holdKeyboard = ref(false)
|
||||||
/// 是否在键盘弹出,点击界面时关闭键盘
|
/// 是否在键盘弹出,点击界面时关闭键盘
|
||||||
const holdKeyboardFlag = ref(true)
|
const holdKeyboardFlag = ref(true)
|
||||||
|
/// 键盘高度
|
||||||
|
const keyboardHeight = ref(0)
|
||||||
|
/// 是否显示键盘
|
||||||
|
const isKeyboardShow = ref(false)
|
||||||
|
|
||||||
///(控制滚动位置)
|
///(控制滚动位置)
|
||||||
const scrollTop = ref(99999);
|
const scrollTop = ref(99999);
|
||||||
@@ -136,6 +145,8 @@
|
|||||||
let commonType = ''
|
let commonType = ''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 打开抽屉
|
// 打开抽屉
|
||||||
const emits = defineEmits(['openDrawer'])
|
const emits = defineEmits(['openDrawer'])
|
||||||
const openDrawer = () => {
|
const openDrawer = () => {
|
||||||
@@ -144,23 +155,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleTouchEnd = () => {
|
const handleTouchEnd = () => {
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
clearTimeout(timer.value)
|
clearTimeout(timer.value)
|
||||||
timer.value = setTimeout(() => {
|
timer.value = setTimeout(() => {
|
||||||
// 键盘弹出时点击界面则关闭键盘
|
// 键盘弹出时点击界面则关闭键盘
|
||||||
if (handleNoHideKeyboard) {
|
if (holdKeyboardFlag.value && isKeyboardShow.value) {
|
||||||
uni.hideKeyboard()
|
uni.hideKeyboard()
|
||||||
}
|
}
|
||||||
holdKeyboardFlag.value = true
|
holdKeyboardFlag.value = true
|
||||||
}, 50)
|
}, 100)
|
||||||
// #endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击输入框、发送按钮时,不收键盘
|
// 点击输入框、发送按钮时,不收键盘
|
||||||
const handleNoHideKeyboard = () => {
|
const handleNoHideKeyboard = () => {
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
holdKeyboardFlag.value = false
|
holdKeyboardFlag.value = false
|
||||||
// #endif
|
}
|
||||||
|
|
||||||
|
// 键盘弹起事件
|
||||||
|
const handleKeyboardShow = (height) => {
|
||||||
|
keyboardHeight.value = height
|
||||||
|
isKeyboardShow.value = true
|
||||||
|
holdKeyboard.value = true
|
||||||
|
// 键盘弹起时调整聊天内容的底部边距并滚动到底部
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollToBottom()
|
||||||
|
}, 150)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 键盘收起事件
|
||||||
|
const handleKeyboardHide = () => {
|
||||||
|
keyboardHeight.value = 0
|
||||||
|
isKeyboardShow.value = false
|
||||||
|
holdKeyboard.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 滚动到底部
|
/// 滚动到底部
|
||||||
@@ -207,6 +232,12 @@
|
|||||||
if(!isSessionActive) {
|
if(!isSessionActive) {
|
||||||
inputMessage.value = ''
|
inputMessage.value = ''
|
||||||
}
|
}
|
||||||
|
// 发送消息后保持键盘状态
|
||||||
|
if (holdKeyboard.value && inputAreaRef.value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
inputAreaRef.value.focusInput()
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
setTimeoutScrollToBottom()
|
setTimeoutScrollToBottom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.chat-container {
|
.chat-container {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: #E9F3F7;
|
background-color: #E9F3F7;
|
||||||
@@ -7,6 +7,8 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
/* 确保在键盘弹起时布局正确 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
.chat-container-bg {
|
.chat-container-bg {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -20,12 +22,10 @@
|
|||||||
|
|
||||||
.chat-content {
|
.chat-content {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -77,13 +77,19 @@
|
|||||||
.footer-area {
|
.footer-area {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 4px 0 24px 0;
|
padding: 4px 0 20px 0; /* 直接设置20px底部安全距离 */
|
||||||
background-color: #E9F3F7;
|
background-color: #E9F3F7;
|
||||||
touch-action: pan-x; /* 仅允许横向触摸滚动 */
|
touch-action: pan-x;
|
||||||
overflow-x: auto; /* 允许横向滚动 */
|
overflow-x: auto;
|
||||||
overflow-y: hidden; /* 禁止垂直滚动 */
|
overflow-y: hidden;
|
||||||
/* 确保高度能够正确计算 */
|
|
||||||
min-height: fit-content;
|
min-height: fit-content;
|
||||||
|
/* 安卓键盘适配 - 使用相对定位配合adjustPan */
|
||||||
|
position: relative;
|
||||||
|
z-index: 1000;
|
||||||
|
transition: padding-bottom 0.3s ease;
|
||||||
|
/* 确保输入区域始终可见 */
|
||||||
|
transform: translateZ(0);
|
||||||
|
-webkit-transform: translateZ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.area-input {
|
.area-input {
|
||||||
|
|||||||
Reference in New Issue
Block a user