方法一
1、问题背景
在评论或者发布内容时经常会用到这样的设计,输入框弹起,然后底部定位的一块区域(通常用于选择一些附加信息,比如图片、话题、表情等)也随之弹起,定位在软键盘上方方便用户选择。但是一般点击输入框,软键盘自动弹起,就会覆盖掉底部定位的元素,而我们是需要底部定位的元素跟随软键盘一起弹起的,这样就方便用户输入的时候也可以选择其他附加信息。
2、我们可以通过uniapp提供的接口获取到软键盘的高度
uni.onKeyboardHeightChange(CALLBACK):监听键盘高度变化,返回参数就是:{ height: number类型,键盘高度 }
可以获取到键盘高度,然后修改定位的bottom即可。
3、遇到问题
当我获取键盘高度定位时,发现底部定位的元素总是跟软键盘间隔一段距离。安卓和ios手机均是如此。就如这样:
4、问题原因
这是因为手机屏幕底部存在虚拟键位,虚拟键位是占了软键盘高度,占了屏幕高度,但是不占屏幕可使用窗口高度的
5、解决方案
知道了原因,其实问题就很好解决了。
uni.getSystemInfo(OBJECT):获取系统信息。
我们可以通过该接口获取到系统信息里的:screenHeight(屏幕高度)、windowHeight(可使用窗口高度)
两者相减即为虚拟键位高度:keyHeight = screenHeight - windowHeight
然后获取到的软键盘高度 减去 虚拟键位高度即可得到定位的高度
setKeyHeight(obj) {
let _sysInfo = uni.getSystemInfoSync()
let _heightDiff = _sysInfo.screenHeight - _sysInfo.windowHeight
let _diff = obj.height - _heightDiff
this.keyHeight = _diff > 0 ? _diff : 0
在iphone上有这样的问题,就是上面的obj.height在键盘隐藏时为0,这个时候就会出现负值,所以需要判断下
6、注意内存泄漏
使用了uni.onKeyboardHeightChange(CALLBACK):监听键盘高度变化,注意需要使用uni.offKeyboardHeightChange(CALLBACK):取消监听键盘高度变化事件,避免内存消耗。
demoCode:
<template class="comment-page">
<div class="comment-component">
<div
class="comment-write"
:style="{
bottom: inputWrapHeight
}"
>
<div class="comment-input">
<textarea
:maxlength="maxlength"
placeholder-style="color:#9796A9"
:placeholder="`评论一下…`"
@focus="inputFocus"
@keyboardheightchange="keyboardheightchange"
@blur="inputBlur"
hold-keyboard="true"
auto-blur="true"
adjust-position="false"
show-confirm-bar="false"
ref="inputRef"
fixed="true"
:focus="focus"
:disabled="disabled"
@input="inputChange"
/>
</div>
<div class="comment-send">
<span class="content-num">剩余{{ calcNums }}字</span>
<div class="send-btn" @click="sendComment">发送</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
maxlength: 100,
focus: false,
inputWrapHeight: '0px',
disabled: false,
calcNums: 100,
platform: 'android',
systemInfo: {},
Keyboard: 0, // 键盘高度
targetNode: null,
machineHeight: 0
};
},
methods: {
inputChange(e) {
if (!e.detail) return;
this.calcNums = this.maxlength - e.detail.value.length;
},
sendComment() {
this.focus = false;
},
inputFocus(e) {
let that = this;
let { screenHeight, screenWidth, statusBarHeight, windowHeight } = this.systemInfo;
this.machineHeight = screenHeight - windowHeight; // 虚位高度
let dp = screenWidth / screenHeight;
if (e) {
let { height } = e.detail; // 获取键盘高度
if (height) this.inputWrapHeight = `${(height) * dp}px`;
}
},
inputBlur() {
this.inputWrapHeight = 0;
},
keyboardheightchange(e) {
console.log(e);
},
show() {},
hide() {},
calcMaskHeight() {
let that = this;
let targetNode = uni.createSelectorQuery().select('.comment-component'); // 获取某个元素
targetNode
.boundingClientRect(function(data) {
// console.log(data.height.toFixed(2)); // 获取元素宽度
that.inputWrapHeight = data.height;
})
.exec();
}
},
mounted() {
let that = this;
// this.calcMaskHeight();
const info = wx.getSystemInfoSync();
console.log(info);
if (info) this.platform = info.platform;
this.systemInfo = info;
}
};
</script>
<style lang="scss" scoped>
.comment-component {
font-family: PingFang-SC-Regular, PingFang-SC;
// width: 100vw;
// height: 100vh;
// height: 100%;
background: transparent;
background: rgba(0, 0, 0, 0.8);
// background: red;
z-index: 99999;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
// top: -10000px;
.comment-write {
position: absolute;
bottom: 0;
// top: 0;
width: 100vw;
height: 160px;
background: #fff;
display: flex;
flex-direction: column;
.comment-input {
// width: 335px;
width:calc(100% - 40px);
height: 85px;
background: #f7f8fa;
margin: 15px auto;
textarea {
width: 100%;
height: 100%;
padding: 10px;
font-size: 14px;
font-weight: 400;
color: #333;
}
}
.comment-send {
padding: 0 20px;
height: 60px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.content-num {
font-size: 12px;
font-weight: 400;
color: #b4b2c0;
}
.send-btn {
cursor: pointer;
width: 65px;
height: 30px;
@include flexCenter;
background: #000000;
border-radius: 2px;
font-size: 14px;
font-weight: 400;
color: #ffffff;
}
}
}
}
</style>
方法二
不需要计算键盘的高度,让输入框自动跟随键盘顶上去( 兼容 ios,android )
使用 textarea 核心属性adjust-position="true" cursor-spacing="140" disable-default-padding="true"
让 cursor-spacing 与输入框高度相同即可
代码案例:
<template class="comment-page">
<div class="comment-component" v-show="showVisiable" @click="touchOther">
<div
class="comment-write"
:style="{
bottom: inputWrapHeight,
}"
@click.stop="noDefault"
>
<div class="comment-input">
<textarea
:maxlength="maxlength"
placeholder-style="color:#9796A9"
:placeholder="`${placeholder}`"
@focus="inputFocus"
@keyboardheightchange="keyboardheightchange"
@blur="inputBlur"
hold-keyboard="true"
auto-blur="true"
adjust-position="true"
:cursor-spacing="cursorSpacing"
disable-default-padding="true"
show-confirm-bar="false"
ref="inputRef"
fixed="true"
:focus="focus"
:disabled="disabled"
@input="inputChange"
:value="writeContent"
/>
</div>
<div class="comment-send">
<span class="content-num">剩余{{ calcNums }}字</span>
<div
class="send-btn"
@click="sendComment"
:class="{ disabled: !writeContent }"
>
发送
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
maxlength: 100,
focus: false,
inputWrapHeight: "0px",
disabled: false,
platform: "android",
systemInfo: {},
Keyboard: 0, // 键盘高度
targetNode: null,
showVisiable: false,
writeContent: "",
callback: null,
placeholder: "评论一下…",
cursorSpacing:140,
};
},
computed: {
calcNums() {
return this.maxlength - this.writeContent.length;
},
},
methods: {
touchOther() {
this.hide();
},
noDefault() {},
inputChange(e) {
if (!e.detail) return;
this.writeContent = e.detail.value;
this.$nextTick(() => {
// #ifdef MP-WEIXIN
uni.setStorage({
key: "commentWriteContent",
data: JSON.stringify(this.writeContent),
});
// #endif
});
},
sendComment() {
if (this.writeContent) {
this.focus = false;
this.hide();
this.callback &&
this.callback({
statusCode: "success",
result: this.writeContent,
});
// #ifdef MP-WEIXIN
setTimeout(() => {
// 清空缓存,输入框数据
uni.removeStorage({
key: "commentWriteContent",
});
this.writeContent = "";
}, 300);
// #endif
} else {
uni.showToast({
title: "请输入评论内容",
duration: 2000,
icon: "none",
});
}
},
inputFocus(e) {
return;
let { screenHeight, screenWidth, statusBarHeight, windowHeight } =
this.systemInfo;
let machineHeight = screenHeight - windowHeight; // 虚位高度
let dp = screenWidth / screenHeight;
if (e) {
let { height } = e.detail; // 获取键盘高度
if (height) this.inputWrapHeight = `${(height - machineHeight) * dp}px`;
}
},
inputBlur() {
this.inputWrapHeight = 0;
},
keyboardheightchange(e) {
console.log(e);
},
show(payload_, callback_) {
// console.log("show方法", payload_, callback_);
this.getCommentStr();
let payloadJudge = Object.prototype.toString.call(payload_);
let callbackJude = Object.prototype.toString.call(callback_);
if (payloadJudge == "[object Function]") this.callback = payload_;
if (callbackJude == "[object Function]") this.callback = callback_;
if (payloadJudge == "[object Object]") {
this.maxlength = payload_.maxlength; // 字数限制
this.placeholder = payload_.payload; // placeholder
}
this.showVisiable = true;
this.$nextTick(() => {
this.focus = true;
});
},
hide() {
this.showVisiable = false;
this.$nextTick(() => {
// this.writeContent = "";
this.callback &&
this.callback({
statusCode: "fail",
result: "",
});
});
},
getCommentStr() {
// 获取缓存数据
let that = this;
// #ifdef MP-WEIXIN
uni.getStorage({
key: "commentWriteContent",
success: function (res) {
console.log("缓存数据", res.data);
that.writeContent = JSON.parse(res.data);
},
});
// #endif
},
},
mounted() {
const info = wx.getSystemInfoSync();
if (info) this.platform = info.platform;
this.systemInfo = info;
},
};
</script>
<style lang="scss" scoped>
.comment-component {
font-family: PingFang-SC-Regular, PingFang-SC;
// width: 100vw;
// height: 100vh;
// height: 100%;
background: transparent;
background: rgba(0, 0, 0, 0.5);
// background: red;
z-index: 99999;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
// top: -10000px;
.comment-write {
position: absolute;
bottom: 0;
// top: 0;
width: 100vw;
height: 160px;
background: #fff;
display: flex;
flex-direction: column;
.comment-input {
// width: 335px;
width: calc(100% - 40px);
height: 85px;
background: #f7f8fa;
margin: 15px auto;
textarea {
width: 100%;
height: 100%;
padding: 10px;
font-size: 14px;
font-weight: 400;
color: #333;
}
}
.comment-send {
padding: 0 20px;
height: 60px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.content-num {
font-size: 12px;
font-weight: 400;
color: #b4b2c0;
}
.send-btn {
cursor: pointer;
width: 65px;
height: 30px;
@include flexCenter;
background: #000000;
border-radius: 2px;
font-size: 14px;
font-weight: 400;
color: #ffffff;
}
.send-btn.disabled {
background: #dae0ea;
}
}
}
}
</style>