uniapp弹出软键盘获取键盘高度不准确,显示输入框

本文介绍了在uniapp中如何处理输入框弹出时底部元素无法准确跟随键盘高度的问题。通过uniapp的onKeyboardHeightChange接口获取键盘高度,并结合getSystemInfo获取的屏幕信息来计算实际的定位高度,从而解决安卓和ios上存在的间距问题。此外,还提供了解决iPhone键盘隐藏时高度为0导致的负值问题,以及避免内存泄漏的注意事项。另外,文中还提到了方法二,即直接使用textarea的adjust-position属性,实现输入框自动跟随键盘。
摘要由CSDN通过智能技术生成

方法一

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>

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值