移动端如何识别键盘弹出

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

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

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


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


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

使用Vue的方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<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>