input聚焦弹出键盘时, 防止自定义导航上移的一种解决方法
发布于 4 年前 作者 duming 3764 次浏览 来自 分享

前提

在开发小程序的过程中,会经常使用到input组件,其聚焦的时候,会在必要时自动上移整个页面以便弹起的键盘不回遮住input组件

但是当页面应用自定义导航时,聚焦时会把自定义导航也上移,而这就不符合我们的预期,我们希望的是导航栏始终固定在顶部,下面的内容上移即可!参见该帖子

为了解决这个问题,我们只好自己来处理页面上移的事情了!

准备工作

首先我们需要先关闭掉输入框自动上移页面的功能

<input type="text" adjust-position="{{false}}" />

接下来我们就要自己处理页面上移的工作了

为了让除了导航栏的区域整体上移, 我们需要先可以定义一个值(top)来表示上移距离

// index.js
Page({
  data: {
    top: 0
  }
})

其次 需要固定好页面的结构, 如下: 我们要做的便是只上移.cointainer这个组件, 故使用top: -{{top}}px来表示内容上移

// index.wxml
<mp-navigation-bar background="#d8d8d8" title="导航栏标题"></mp-navigation-bar>
<view class="container" style="position: relative; top: -{{top}}px">
  内容区域
</view>

计算上移距离

我们先思考什么情况下, 页面需要上移?

显然是input距离底部的距离小于弹出的键盘高度的时候需要上移, 而上移的距离便是__距离底部的距离与键盘高度的差__

那么只需要知道这两个值便可实现该功能了.

键盘高度

翻阅input的文档, 我们发现监听bindfocus或者bindkeyboardheightchange事件都可以获取到键盘的高度

// index.wxml
# index.wxml
<input id="input1" type="text" adjust-position="{{false}}" bindfocus="onHandleFocus" bindblur="onBlur" />

// index.js
onHandleFocus (e) {
    console.log('focus', e)
    const keyboradHeight = e.detail.height
}

距离底部的距离

首先我们需要货值输入框的位置, 这里可以使用SelectorQuery来获取输入框的位置


# index.js
onHandleFocus (e) {
    console.log('focus', e)
    const keyboradHeight = e.detail.height
    const id = e.currentTarget.id
    this.createSelectorQuery()
      .select(`#${id}`)
      .boundingClientRect(rect => {
        console.log('==> rect', rect)
        
      }).exec()
}

获取到的rect对象同DOM的getBoundingClientRect, 然后我们再观察这张图片:

显然要计算输入框距离底部的距离只需用显示高度减去bottom即可

页面的显示高度可以用如下方法获得

const { windowHeight } = wx.getSystemInfoSync()

最后我们上诉思路整理成对应代码


# index.js
onHandleFocus (e) {
    console.log('focus', e)
    const keyboradHeight = e.detail.height
    const id = e.currentTarget.id
    this.createSelectorQuery()
      .select(`#${id}`)
      .boundingClientRect(rect => {
        console.log('==> rect', rect)
        const { windowHeight } = wx.getSystemInfoSync()
        const bottom = windowHeight - rect.bottom

        if (bottom > keyboradHeight) {
          // 距离足够, 不需要上移
          return
        }

        this.setData({
          top: keyboradHeight - bottom
        })
      }).exec()
}

完整代码见该代码片段

尾声

该方法虽然能够解决标题所述的问题,当也存有其他问题:

  • 页面结构必须固定结构(分为标题-内容两大块)
  • 所有的input都必须加上id,否则createSelectorQuery选择器没法找到对应的input,且必须监听focusblur方法。
  • 最外层的内容viewtop样式被占用

PS: 计算上移距离的这部分代码可以写成一个behavior方便其他页面直接引入

回到顶部