移动端如何识别键盘弹出

31 阅读2分钟

Date: 2022-04-15

在开发移动端的时候,我们可能需要识别键盘是否弹窗,然后处理一些特殊逻辑,那么如何识别该状态呢?

我们可能很容易想到监听输入框的 focusblur 事件,然后部分安卓键盘右上角有收起操作,收起的时候并不会执行 blur 事件,输入框光标仍然在,导致我们无法精准的识别。

js_keyboard_android1.jpg

既然通过 focusblur 无法识别,那么我们很容易想到监听 resize 的触发,分析 iOSAndroid 激活时的样式 当页面没有设置100%高度时,可以看到 iOSAndroid 激活键盘时,键盘会盖在页面的上方。


当页面设置100%高度,使用flex布局,header顶部固定,footer底部固定,中间区域滚动时,可以看到 iOS 键盘仍然时盖在上面,而 Android 激活键盘则会将页面往上顶。


Android 激活键盘会会触发 resize,而 iOS 当输入框不在顶部时会触发 scroll 事件,在顶部时不会触发 scroll 事件,我们使用 focusinfocusout 来捕获。

使用Vue的方式如下:

<template>
  <div class="keyboard-view">
    <header>header</header>

    <main>
      <div class="empty-box"></div>
      <br>
      <div>
        <input type="text" placeholder="请输入">
      </div>
      <br>
      <div class="empty-box"></div>
    </main>

    <footer>footer</footer>

    <div class="fixed-mask">
      键盘state: {{ state }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'KeyboardVisible',
  data () {
    return {
      state: '失焦',
      docHeight: document.documentElement.clientHeight
    }
  },
  mounted () {
    this.keyboardShowListener()
  },
  methods: {
    keyboardShowListener () {
      let self = this
      // 全局监听激活
      function focusInFn () {
        self.state = '激活'
        self.keyboardShowFn()
      }
      // 全局监听失焦
      function focusOutFn () {
        self.state = '失焦'
        self.keyboardHideFn()
      }
      // 监听iOS(当输入框在页面非顶部区域时都会触发)
      function scrollFn () {
        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        if (scrollTop == 0) {
          self.state = '失焦'
          self.keyboardHideFn()
        } else {
          self.state = '激活'
          self.keyboardShowFn()
        }
      }
      // 监听安卓
      function resizeFn () {
        let docHeight = document.documentElement.clientHeight
        if (docHeight == self.docHeight) {
          self.state = '失焦'
          self.keyboardHideFn()
        } else {
          self.state = '激活'
          self.keyboardShowFn()
        }
      }
      document.body.addEventListener('focusin', focusInFn, false)
      document.body.addEventListener('focusout', focusOutFn, false)
      document.addEventListener('scroll', scrollFn, false)
      window.addEventListener('resize', resizeFn, false)
      this.$once('hook:beforeDestroy', function () {
        document.body.removeEventListener('focusin', focusInFn, false)
        document.body.removeEventListener('focusout', focusOutFn, false)
        document.removeEventListener('scroll', scrollFn, false)
        window.removeEventListener('resize', resizeFn, false)
      })
    },
    keyboardShowFn () {
      // alert('keyboardShowFn')
    },
    keyboardHideFn () {
      // alert('keyboardHideFn')
    }
  }
}
</script>

<style lang="scss" scoped>
.keyboard-view{
  height: 100%;
  display: flex;
  flex-direction: column;
  header{
    height: 40px;
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
    display: flex;
    justify-content: center;
    align-items: center;
  }
  footer{
    height: 40px;
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
    display: flex;
    justify-content: center;
    align-items: center;
  }
  main{
    padding: 16px;
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  input{
    width: 100%;
    height: 40px;
    border: 1px solid #ccc;
    padding: 10px;
    box-sizing: border-box;
  }
  .empty-box{
    height: 500px;
    background-color:#ccc;
  }
  .fixed-mask{
    width: 100px;
    background-color: rgba(0, 0, 0, 0.5);
    position: fixed;
    right: 0;
    top: 300px;
    color: #fff;
    padding: 5px;
    font-size: 12px;
  }
}
</style>