前景:需要开发一个聊天系统,界面需要和微信一样,输完内容直接点发送内容,内容发送完成,但input不失焦,发送可以用input的@confirm事件执行,也可以是在别的dom上绑定发送。遇到两个难点
- 点发送input马上失焦
- input聚焦后,会把页面上顶,聊天内容就被顶走了,看不到了
DOM结构
<view class="content">
<view class="chat">
<scroll-view scroll-y="true" class="scroll" :scroll-top="scrollTop" scroll-with-animation :show-scrollbar="true">
<view class="chat-content" v-for="(item, index) in chatData" :key="index">
<view class="chat-list" v-if="item.type == 2">
<image class="c-l-head" @click="switchSpeakers(item)" :src="item.head" />
<view class="c-l-center">{{ item.content }}</view>
</view>
<view class="chat-list-right" v-if="item.type == 1">
<view class="c-l-center">{{ item.content }}</view>
<image class="c-l-head" @click="switchSpeakers(item)" :src="item.head" />
</view>
<view class="caht-time" v-if="item.type == 3"
><text class="c-t-time c-t-nobg">{{ item.content }}</text></view
>
</view>
<view class="kongb" style="height: 14px; flex: 1"></view>
</scroll-view>
</view>
<view class="bottom">
<view class="bottom-top">
<view class="b-t-l">
<image class="bottom-icon" src="/static/chat1.png" />
</view>
<view class="b-t-c">
<input class="uni-input" v-model="value" :style="{ marginBottom: isFoucs ? '15px' : '5px' }" confirm-type="send" @click="isChange = true" :focus="isFoucs" @blur="blur" @focus="foucs" @confirm="confirm" placeholder="" />
</view>
<view class="b-t-r">
<image class="bottom-icon t-r-icon" src="/static/chat2.png" />
<image class="bottom-icon" src="/static/chat3.png" />
</view>
</view>
</view>
</view>
CSS
.content {
width: 100%;
height: 100%;
position: absolute;
display: flex;
flex-direction: column;
justify-content: flex-end;
background: #ededed;
.chat {
flex: 1;
background: #ededed;
width: 100%;
position: relative;
.scroll {
position: absolute;
width: 100%;
height: 100%;
bottom: 0;
left: 0;
top: 0;
display: flex;
flex-direction: column;
}
}
.bottom {
width: 100%;
background: rgba(245, 245, 245, 0.98);
position: relative;
display: flex;
flex-direction: column;
padding-bottom: calc(env(safe-area-inset-bottom) + 1rpx);
.spokesman {
width: 80upx;
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
top: -70px;
background: #fff;
border: 2px solid #fff;
left: 20upx;
&::after {
content: '';
width: 16upx;
height: 16upx;
background: #fff;
border-radius: 4upx;
transform: rotate(45deg);
position: absolute;
left: 50%;
bottom: -10upx;
margin-left: -10upx;
}
.s-head {
width: 80upx;
height: 80upx;
border-radius: 10upx;
}
.sp-text {
color: #333;
font-size: 11px;
text-align: center;
background: #fff;
position: relative;
z-index: 2;
}
}
.bottom-top {
width: 100%;
display: flex;
flex-direction: row;
padding-top: 7px;
border-top: 1px solid #dad7d3;
box-sizing: border-box;
align-items: flex-start;
.b-t-c {
flex: 1;
.uni-input {
height: 40px;
flex: 1;
padding: 5px 10px;
font-size: 16px;
background: #ffff;
border-radius: 10upx;
color: #000;
margin-bottom: 5px;
box-sizing: border-box;
}
}
.b-t-l {
padding: 0 20upx;
display: flex;
align-items: center;
padding-top: 7px;
}
.b-t-r {
padding: 0 20upx;
display: flex;
align-items: center;
padding-top: 7px;
.t-r-icon {
margin-right: 25upx;
}
}
.bottom-icon {
width: 54rpx;
height: 54rpx;
}
}
.bottom-k {
width: 100%;
height: 24px;
}
}
}
这样写,然后就会上顶,还会输完以后马上失焦
解决失焦问题
属性名 | 类型 | 默认值 | 说明 | 平台差异说明 | 备注 |
confirm-hold | Boolean | false | 点击键盘右下角按钮时是否保持键盘不收起 | App(3.3.7+)、H5 (3.3.7+)、微信小程序、支付宝小程序、百度小程序、QQ小程序、京东小程序 | 使用input自带的发送按钮,添加这个属性后,发送完成后就不会失焦了 |
以上测试还有两个问题
- 聊天内容上顶
- input输入框位置不对
聊天内容上顶可以添加adjust-position这个属性
属性名 | 类型 | 默认值 | 说明 | 平台差异说明 | 备注 |
adjust-position | Boolean | true | 键盘弹起时,是否自动上推页面 | App-Android(vue 页面 softinputMode 为 adjustResize 时无效,使用 x5 内核时无效)、微信小程序、百度小程序、QQ小程序、京东小程序 | ~ |
添加后,不会上顶了,但是这样也把input给挡住了,无法看到input框了, 因为我们设置的.input样式是position:fixed; bottom:0;
找到问题解决问题,知道是fixed的bottom:0,导致input框被键盘遮住,那就获取这个键盘高度,并且,把.input的bottom:键盘高度就解决这个问题了
<!-- Dom结构 -->
<view class="bottom" :style="{bottom:bottomHeight}">
input框dom
<view>
methods: {
// 键盘弹出时执行
keyboardheightchange(ev){
const res_keyboard = uni.getSystemInfoSync();
// 获取键盘高度 - 刘海屏手机下方的空白高度 = input的bottom高度
const h = (ev.detail.height ? ev.detail.height - res_keyboard.safeAreaInsets.bottom : 0)
this.bottomHeight = h + 'px';
// 计算聊天内容主体高度
this.computedHeight(h)
},
// 计算高度
computedHeight(bottomHeight) {
let that = this;
that.screenHeight = '100vh';
const query = uni.createSelectorQuery().in(this); //这样写就只会选择本页面组件的类名box的
query.select('.chat').boundingClientRect(); // 聊天内容主体
query.select('.bottom').boundingClientRect(); // input框入框主体
query.exec(function(res) {
if (bottomHeight) {
// 键盘弹出
that.screenHeight = res[0].height - res[1].height - bottomHeight + 'px';
this.scrollTop += 100;
} else {
// 键盘收起
that.screenHeight = res[0].height - res[1].height + 'px';
}
});
},
}
最后,完成此功能