uniapp兼容性问题之 ios 端软键盘收起后页面错乱

1,210 阅读2分钟

一、问题描述

ios端使用uniapp开发的h5兼容性问题: 使用uniapp的input/textarea 组件输入完成后,软键盘收起但页面还保持上推布局(如下图 1),输入时键盘弹起会挤压屏幕视口,页面由于键盘挤压会上推(如下图 2),但键盘收起时页面正常情况下会下落到之前布局(如下图 3)。

图1:ec24465925.png 图2:48c596c51c.png 图3:d0214422af.png

对于这种键盘收起但页面还保持上推的情况,会影响页面其他的按钮触发点击或者其他的点击操作,此情形下点击按钮会失效,需要滑动拖拽页面以恢复页面布局正常后才能操作。

二、问题排查

最开始以为是偶现事件,后来发现是 如果连着输入几个 input/textarea 框再收起键盘就会触发,如果只是输入一个 input/textarea就收起键盘不会触发。但是出现这种情况 可以手动拖动页面就下滑回来页面可以正常操作点击。
由于设置 adjust-position:true,所以 ios 机上键盘弹起时,会自动上推页面。

截屏2024-07-16 15.01.37.png

截屏2024-07-16 15.02.56.png

但当连续点击多个 input/textarea 框后点击其他空白区域或者点击键盘“完成”按钮,收起键盘时 所有 input/textarea 框失焦,键盘收起,猜测此时键盘收起时页面的重新渲染时机有问题。键盘收起时页面的滚动高度会重新计算后渲染。

所以解决方法是需要在收起键盘时重新触发页面滚动及页面高度调整。

三、解决方案

针对 ios 机型 监听软键盘收起且页面所有 input 输入框失去焦点时 执行页面滚动。
核心方法如下:

  • 计算 scrollTop时 使用 scrollHeight - clientheight 代替 document.documentElement.scrollTop || document.body.scrollTop更准确
  • window.scrollTo 代替 uni.pageScrollTo 效果更好更丝滑;如果只使用uni.pageScrollTo({scrollTop: scrollTop}) 不会生效,需要使用两次,但是两次 pageScrollTo页面滚动效果不好会抖动。
const scrollPage = () => {
  const clientheight = document.documentElement.clientHeight || document.body.clientHeight || 0
  const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight || 0
  const scrollTop = scrollHeight - clientheight || 0
  setTimeout(() => {
    // 滚动到页面对应高度
    window.scrollTo(0, scrollTop)
  }, 100)
}

以textarea为例 完整示例逻辑:

<template>
  <div class="input-1">
     <textarea
       v-model="value1"
       placeholder="请输入"
       maxlength="50"
       @blur="onTextareaBlur"
       @focus="onTextareaFocus"
     />
 </div>
 <div class="input-2">
    <textarea
      v-model="value2"
      placeholder="请输入"
      maxlength="50"
      @blur="onTextareaBlur"
      @focus="onTextareaFocus"
    />
 </div>
</template>
<script lang="ts" setup>
// import ...

const isTextareaFocus = ref(false)
const onTextareaBlur = () => {
  isTextareaFocus.value = false
}
const onTextareaFocus = () => {
  isTextareaFocus.value = true
}

const scrollPage = () => {
  const clientheight = document.documentElement.clientHeight || document.body.clientHeight || 0
  const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight || 0
  const scrollTop = scrollHeight - clientheight || 0
  setTimeout(() => {
    // 滚动到输入后的页面对应高度
    window.scrollTo(0, scrollTop)
  }, 100)
}
onMounted(() => {
  // onKeyboardHeight为封装的监听键盘高度变化事件
  onKeyboardHeight((height: number)=> { 
   // ios端键盘收起且页面失焦后手动下滑页面
   if (this.deviceFrame === 'ios' && height === 0 && isTextareaFocus.value === false) {
     // 滚动页面
     srcollPage()
   }
  })
})
</script>