故事背景:这些天开发一个小程序,功能是发送消息,输入框输入内容后,点击发送,消息显示在界面上。功能很简单,但是在实现后发现一个很不好的交互体验,就是点击发送后键盘会先收起,然后再显示。如此突兀的交互体验让我非常难以接受。所以就尝试解决这个问题,从网上搜索了很多方法,也查看了微信小程序的api文档,下面就是我解决的过程,在此记录一下
先前置说明一下简单代码结构
<view class="container">
<!-- 消息显示区域 -->
<scroll-view
class="message-area"
bind:touchend="bindHideKeyboard"
scroll-y
scroll-with-animation
scroll-top="{{scrollTop}}"
scroll-into-view="{{'msg' + (messages.length - 1)}}"
>
<block wx:for="{{messages}}" wx:key="index">
<view id="msg{{index}}" class="message {{item.type}}">
<text class="msg-content">{{item.content}}</text>
<text class="msg-time">{{item.time}}</text>
</view>
</block>
</scroll-view>
<!-- 输入区域 -->
<view class="input-area">
<input
class="input-box"
placeholder="输入消息..."
value="{{inputValue}}"
focus="{{isFocus}}"
bindinput="onInput"
bindconfirm="onSend"
cursor-spacing="20"
confirm-hold="{{true}}"
adjust-position="{{true}}"
hold-keyboard="{{true}}"
/>
<button
class="send-btn {{inputValue ? 'active' : ''}}"
bindtap="onSend"
hover-class="none"
>
发送
</button>
</view>
</view>
Page({
data: {
inputValue: '', // 输入框内容
messages: [], // 消息列表
scrollTop: 0, // 滚动条位置
isFocus: false // 输入框是否聚焦
},
onLoad() {
},
// 添加系统消息
addSystemMessage(content) {
const messages = this.data.messages;
messages.push({
content: content,
type: 'received',
time: this.getCurrentTime()
});
this.setData({ messages });
this.scrollToBottom();
},
// 输入框内容变化
onInput(e) {
this.setData({
inputValue: e.detail.value
});
},
// 发送消息
onSend() {
const message = this.data.inputValue.trim();
if (!message) return;
// 添加用户消息
const messages = this.data.messages;
messages.push({
content: message,
type: 'sent',
time: this.getCurrentTime()
});
this.setData({
messages,
inputValue: '', // 清空输入框
isFocus: true // 保持输入框聚焦
});
// 滚动到底部
this.scrollToBottom();
// 模拟回复
this.simulateReply();
},
// 模拟回复
simulateReply() {
setTimeout(() => {
const replies = [
'收到您的消息',
'我明白了',
'感谢您的分享',
'这个问题我需要查一下',
'请稍等,正在处理'
];
const randomReply = replies[Math.floor(Math.random() * replies.length)];
this.addSystemMessage(randomReply);
}, 800);
},
// 滚动到底部
scrollToBottom() {
this.setData({
scrollTop: 99999 // 设置足够大的值确保滚动到底部
});
},
// 获取当前时间
getCurrentTime() {
const now = new Date();
return `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
},
bindHideKeyboard: function (e) {
wx.hideKeyboard()
}
});
/* 全局样式 */
page {
background-color: #f5f7fb;
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", STHeiti, "Microsoft Yahei", Tahoma, Simsun, sans-serif;
}
/* 容器样式 */
.container {
display: flex;
flex-direction: column;
height: 100vh;
background: linear-gradient(180deg, #6a11cb 0%, #2575fc 100%);
}
/* 消息区域 */
.message-area {
flex: 1;
padding: 30rpx;
overflow: auto;
box-sizing: border-box;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 60vh;
color: rgba(255, 255, 255, 0.6);
}
.empty-icon {
width: 160rpx;
height: 160rpx;
opacity: 0.7;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 32rpx;
margin-bottom: 15rpx;
}
.empty-tip {
font-size: 26rpx;
}
/* 消息样式 */
.message {
max-width: 75%;
padding: 20rpx 30rpx;
margin-bottom: 40rpx;
border-radius: 16rpx;
position: relative;
word-break: break-word;
animation: fadeIn 0.3s ease-out;
}
.message.sent {
background: #ffffff;
border-bottom-right-radius: 4rpx;
align-self: flex-end;
margin-left: auto;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
}
.message.received {
background: #e5f0ff;
border-bottom-left-radius: 4rpx;
margin-right: auto;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
}
.msg-content {
font-size: 32rpx;
line-height: 1.5;
color: #333;
display: block;
}
.msg-time {
font-size: 22rpx;
color: #999;
display: block;
text-align: right;
margin-top: 10rpx;
}
/* 输入区域 */
.input-area {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background: white;
border-top: 1rpx solid #eaeef5;
}
.input-box {
flex: 1;
background: #f5f7fb;
border-radius: 50rpx;
padding: 20rpx 30rpx;
font-size: 32rpx;
height: 80rpx;
margin-right: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03) inset;
}
.send-btn {
width: 80rpx;
height: 80rpx;
background: transparent;
padding: 0;
margin: 0;
border: none;
border-radius: 10rpx;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
}
.send-btn.active {
background: linear-gradient(to right, #08a0e9, #0575e6);
}
.send-icon {
width: 50rpx;
height: 50rpx;
}
/* 动画 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
先说说网上搜索以及ai生成的方法,网上好多文章说因为input失焦,所以键盘会收起,所以就给input重新聚焦 方法是这样的,以下是简单的代码
<input
focus={isFocus}
/>
Page({
data: {
isFocus: false
},
// 发送消息
onSend() {
const message = this.data.inputValue.trim();
if (!message) return;
// 添加用户消息
const messages = this.data.messages;
messages.push({
content: message,
type: 'sent',
time: this.getCurrentTime()
});
this.setData({
messages,
inputValue: '', // 清空输入框
isFocus: true // 保持输入框聚焦
});
},
})
这样虽然键盘是重新显示了,但是这样有一个很明显的问题,键盘在不停地消失-显示,很明显不是我们需要的交互体验,所以这种方式直接pass掉。
有问题的效果展示
网上大部分说的是这种,不知道是不是我搜索的关键词有问题,搜到的解决方案不是很多
现在说说我的解决方案,在查看小程序api的时候,input组件有这样一个属性hold-keyboard,它的能力是“focus时,点击页面的时候不收起键盘”,也就是说这个属性设置为true后,在点击页面的时候键盘都不会收起来,
这不正是我们需要的能力吗。只要把这个属性设置上,我们就实现了,我可真是个小机灵鬼。
但是!!!加上后就很怕怕了,键盘再也收不起来了,我赶紧去看下文档,还好有取消的方法wx.hideKeyboard(),快快快,赶紧把我们砰砰跳的小心脏按回去。
我在需要点击时需要取消键盘的地方加上了这个方法,一实验,嘿,果然可以。实现的效果和微信聊天就差不多了。完整的代码在文章首部的就是,大家可以直接在微信开发者工具上直接体验下。
简单记录一下开发过程中遇到的问题,提升自己解决问题的能力
如果有掘友还有更好更完美的解决方案,欢迎在评论区分享~~~
同时欢迎掘友对这篇文章指正,有什么好的协作方法可以在评论区分享下,感激不尽o( ̄▽ ̄)d
下面是我开发的小程序,欢迎体验,也欢迎掘友们提供思路,看看还可以加什么功能