作者:超神熊猫
在移动端开发经常会遇到一些交互需要通过判断手机键盘是否被唤起来做的,说到判断手机键盘弹起和收起,有遇到过的同学,应该都知道,安卓和ios判断手机键盘是否弹起的写法是有所不同的
- IOS端可以通过
focusin
focusout
这两个事件来监听
window.addEventListener('focusin', () => {
// 键盘弹出事件处理
alert("ios键盘弹出事件处理")
});
window.addEventListener('focusout', () => {
// 键盘收起事件处理
alert("ios键盘收起事件处理")
})
- 安卓只能通过
resize
来判断屏幕大小是否发生变化来判断
由于某些 Android 手机收起键盘,输入框不会失去焦点,所以不能通过聚焦和失焦事件来判断。但由于窗口会变化,所以可以通过监听窗口高度的变化来间接监听键盘的弹起与收回。
const innerHeight = window.innerHeight
window.addEventListener('resize', () => {
const newInnerHeight = window.innerHeight;
if (innerHeight > newInnerHeight) {
// 键盘弹出事件处理
alert("android 键盘弹出事件");
} else {
// 键盘收起事件处理
alert("android 键盘收起事件处理")
}
})
- 因为ios和安卓的处理不一样,所以还需要判断系统的代码
const ua = typeof window === 'object' ? window.navigator.userAgent : '';
let _isIOS = -1;
let _isAndroid = -1;
export function isIOS() {
if (_isIOS === -1) {
_isIOS = /iPhone|iPod|iPad/i.test(ua) ? 1 : 0;
}
return _isIOS === 1;
}
export function isAndroid() {
if (_isAndroid === -1) {
_isAndroid = /Android/i.test(ua) ? 1 : 0;
}
return _isAndroid === 1;
}
使用
<template>
<form class="keyboard-box" v-keyboard:keyboardFn>
<!-- 输入任意文本 -->
<van-field v-model="text" label="文本" />
<!-- 输入手机号,调起手机号键盘 -->
<van-field v-model="tel" type="tel" label="手机号" />
<!-- 允许输入正整数,调起纯数字键盘 -->
<van-field v-model="digit" type="digit" label="整数" />
<!-- 允许输入数字,调起带符号的纯数字键盘 -->
<van-field v-model="number" type="number" label="数字" />
<van-field v-model="textarea" type="textarea" label="textarea" />
<!-- 输入密码 -->
<van-field v-model="password" type="password" label="密码" />
<van-radio-group v-model="radio" direction="horizontal" class="radio-group">
<van-radio name="1">单选框 1</van-radio>
<van-radio name="2">单选框 2</van-radio>
</van-radio-group>
</form>
</template>
<script>
import keyboard from './keyboard'
export default {
directives: { keyboard },
data() {
return {
text: '',
tel: '',
digit: '',
number: '',
password: '',
textarea: '',
radio: '1'
}
},
methods: {
keyboardFn(val) {
this.$toast(val ? '键盘弹起来了' : '键盘收起了')
}
}
}
</script>
问题
- 复选框、单选框的点击也会导致
focusin
和focusout
的触发,我们需要处理一下,使其点击复选框、单选框这类标签的时候不触发我们的回调函数
// 主要是通过判断一下当前被focus的dom类型
// document.activeElement.tagName
// tagName为输入框的时候才算触发键盘弹起
const activeDom = document.activeElement.tagName
if(!['INPUT', 'TEXTAREA'].includes(activeDom)) {
console.log('只有')
}
- 当有横屏功能的时候,
resize
也会被触发
增加宽度是否有改变的判断,没有改变,才是真正的键盘弹起
//初始化的时候获取一次原始宽度
const originWidth = document.documentElement.clientWidth || document.body.clientWidth
//结合处理复选框、单选框的点击也会导致`focusin` 和`focusout` 的触发问题的完整回调写法
function callbackHook(cb) {
const resizeWeight = document.documentElement.clientWidth || document.body.clientWidth
const activeDom = document.activeElement.tagName
if(resizeWeight !== originWidth || !['INPUT', 'TEXTAREA'].includes(activeDom)) {
return isFocus = false
}
cb && cb()
}
- 怎么传入回调函数,灵活使用
v-指定: fn 传入函数,在指令里面通过执行回调的时候传出参数,来区分是键盘弹起还是收起
//绑定指令的同时传入回调函数
v-keyboard:keyboardFn
methods: {
keyboardFn(val) {
//val true 键盘弹起 false 键盘收起
this.$toast(val ? '键盘弹起来了' : '键盘收起了')
}
}
建议
使用应当要注意销毁,也需要尽量减少绑定指令的次数,一般在form表单上绑定一个,即可监听这个表单下的所有输入框是否触发手机键盘唤起了