我是如何做到“小程序发送消息后,键盘仍然不收起的”

220 阅读5分钟

故事背景:这些天开发一个小程序,功能是发送消息,输入框输入内容后,点击发送,消息显示在界面上。功能很简单,但是在实现后发现一个很不好的交互体验,就是点击发送后键盘会先收起,然后再显示。如此突兀的交互体验让我非常难以接受。所以就尝试解决这个问题,从网上搜索了很多方法,也查看了微信小程序的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后,在点击页面的时候键盘都不会收起来, ding.png这不正是我们需要的能力吗。只要把这个属性设置上,我们就实现了,我可真是个小机灵鬼。

但是!!!加上后就很怕怕了,键盘再也收不起来了,我赶紧去看下文档,还好有取消的方法wx.hideKeyboard(),快快快,赶紧把我们砰砰跳的小心脏按回去。

我在需要点击时需要取消键盘的地方加上了这个方法,一实验,嘿,果然可以。实现的效果和微信聊天就差不多了。完整的代码在文章首部的就是,大家可以直接在微信开发者工具上直接体验下。

简单记录一下开发过程中遇到的问题,提升自己解决问题的能力

如果有掘友还有更好更完美的解决方案,欢迎在评论区分享~~~

同时欢迎掘友对这篇文章指正,有什么好的协作方法可以在评论区分享下,感激不尽o( ̄▽ ̄)d

下面是我开发的小程序,欢迎体验,也欢迎掘友们提供思路,看看还可以加什么功能

智能识垃圾二维码.png