存在问题
做了一个记录页面(类似单方聊天页),输入框在底部;当弹出键盘时,页面整体上移,页面头信息会消失不见
需要实现效果:
比如一个记录页面,需要在键盘弹出时:
- 底部的输入框跟随键盘上弹
- 页面头固定在顶部不动
- 聊天信息区域(即内容区)调整高度,该区域局部滚动
解决方法
- 底部输入框fixed定位在底部,使用输入框的@focus获取键盘高度,更改输入框
bottom;@blur
时恢复bottom=0
; - 使用包含页面头和内容区
- container的padding-bottom设置为输入框高度+输入框bottom,避免被输入框和键盘遮挡;并设置为flex column布局
- 头部定高(如果不定高可以不设置);
- 内容区设flex-grow:1,overflow-y:auto; 使其自适应高度并实现滚动;
实现代码
<template><view><view class="container" :style="{'padding-bottom': `${52+inputBottom}px`}"><view class="header">我是头部</view><scroll-view class="content" :scroll-y="true" :scroll-top="scrollTop"><view><view class="message" v-for="(item,index) in records" :key="index"><view class="message-content" v-html="item.content"></view><view class="message-time">{{item.updateTime}}</view></view></view></scroll-view></view><view class="bottom-textarea" :style="{bottom: inputBottom+'px'}"><view class="textarea-container"><textareav-model="recordInput":maxlength="-1":auto-height="true":show-confirm-bar="false":cursor-spacing="10":fixed="true":adjust-position="false"@focus="focusTextarea"@blur="blurTextarea"/></view><button @click="addRecord" class="primary-btn">记录</button></view></view>
</template><script>
export default {data() {return {records: [],recordInput: "",itemAverageHeight: 500, //每条数据平均高度,为确保能滚到底部,可以设置大一些scrollTop: 1000,inputBottom: 0,};},methods: {getList() {uni.showNavigationBarLoading();// 获取记录信息this.$api.getRecords().then((res) => {this.records = res.reverse().map((item) => ({...item,content: item.content.replace(/\n/g, "<br/>"),}));if (this.records.length > 0)this.scrollTop = this.itemAverageHeight * this.records.length;}).finally(() => {uni.hideNavigationBarLoading();});},addRecord() {const trueValue = this.recordInput.trim();this.$api.addRecord(trueValue).then(() => {this.records.push({content: trueValue.replace(/\n/g, "<br/>"),updateTime: new Date(),});this.recordInput = "";this.scrollTop = this.scrollTop + this.itemAverageHeight; //滚到底部});},focusTextarea(e) {this.inputBottom = e.detail.height;this.scrollTop += 1; //滚到底部},blurTextarea(e) {this.inputBottom = 0;this.scrollTop += 1; //滚到底部},},onLoad(options) {this.getList();},
};
</script><style lang="less">
@left-right-margin: 40rpx;
.container {width: 100vw;height: 100vh;box-sizing: border-box;padding-bottom: 52px;display: flex;flex-direction: column;.header {flex-shrink: 0;padding: 0px @left-right-margin 32rpx @left-right-margin;}.content {flex-grow: 1;overflow: auto;.message {margin: 0px @left-right-margin 32rpx;display: flex;flex-direction: column;align-items: flex-end;.message-content {width: auto;max-width: calc(100vw - 80rpx);word-wrap: break-word;box-sizing: border-box;padding: 32rpx;line-height: 48rpx;background: pink;border-radius: 16rpx 0px 16rpx 16rpx;}.message-time {line-height: 32rpx;margin-top: 16rpx;}}}
}
.bottom-textarea {position: fixed;bottom: 0px;left: 0px;right: 0px;background-color: #f2f2f2;border-top: 2rpx solid rgba(226, 226, 226, 1);padding: 6px 20px;display: flex;align-items: flex-end;.textarea-container {flex: 1;min-height: 80rpx;background: rgba(255, 255, 255, 1);border-radius: 8rpx;box-sizing: border-box;padding: 20rpx 16rpx;> textarea {max-height: 250rpx;font-size: 36rpx;color: rgba(8, 8, 8, 1);width: auto;}}> button {flex-shrink: 0;height: 80rpx;margin: 0;margin-left: 16rpx;}
}
</style>