【W(wǎng)eb技術(shù)】1774- 前端怎么監(jiān)聽(tīng)手機(jī)鍵盤(pán)是否彈起

作者:超神熊貓
原文:https://juejin.cn/post/7117814358259793933
在移動(dòng)端開(kāi)發(fā)經(jīng)常會(huì)遇到一些交互需要通過(guò)判斷手機(jī)鍵盤(pán)是否被喚起來(lái)做的,說(shuō)到判斷手機(jī)鍵盤(pán)彈起和收起,有遇到過(guò)的同學(xué),應(yīng)該都知道,安卓和ios判斷手機(jī)鍵盤(pán)是否彈起的寫(xiě)法是有所不同的
-
IOS端可以通過(guò) focusinfocusout這兩個(gè)事件來(lái)監(jiān)聽(tīng)
window.addEventListener('focusin', () => {
// 鍵盤(pán)彈出事件處理
alert("ios鍵盤(pán)彈出事件處理")
});
window.addEventListener('focusout', () => {
// 鍵盤(pán)收起事件處理
alert("ios鍵盤(pán)收起事件處理")
})
-
安卓只能通過(guò) resize來(lái)判斷屏幕大小是否發(fā)生變化來(lái)判斷
由于某些 Android 手機(jī)收起鍵盤(pán),輸入框不會(huì)失去焦點(diǎn),所以不能通過(guò)聚焦和失焦事件來(lái)判斷。但由于窗口會(huì)變化,所以可以通過(guò)監(jiān)聽(tīng)窗口高度的變化來(lái)間接監(jiān)聽(tīng)鍵盤(pán)的彈起與收回。
const innerHeight = window.innerHeight
window.addEventListener('resize', () => {
const newInnerHeight = window.innerHeight;
if (innerHeight > newInnerHeight) {
// 鍵盤(pán)彈出事件處理
alert("android 鍵盤(pán)彈出事件");
} else {
// 鍵盤(pán)收起事件處理
alert("android 鍵盤(pán)收起事件處理")
}
})
-
因?yàn)閕os和安卓的處理不一樣,所以還需要判斷系統(tǒng)的代碼
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="文本" />
<!-- 輸入手機(jī)號(hào),調(diào)起手機(jī)號(hào)鍵盤(pán) -->
<van-field v-model="tel" type="tel" label="手機(jī)號(hào)" />
<!-- 允許輸入正整數(shù),調(diào)起純數(shù)字鍵盤(pán) -->
<van-field v-model="digit" type="digit" label="整數(shù)" />
<!-- 允許輸入數(shù)字,調(diào)起帶符號(hào)的純數(shù)字鍵盤(pán) -->
<van-field v-model="number" type="number" label="數(shù)字" />
<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 ? '鍵盤(pán)彈起來(lái)了' : '鍵盤(pán)收起了')
}
}
}
</script>
問(wèn)題
-
復(fù)選框、單選框的點(diǎn)擊也會(huì)導(dǎo)致
focusin和focusout的觸發(fā),我們需要處理一下,使其點(diǎn)擊復(fù)選框、單選框這類(lèi)標(biāo)簽的時(shí)候不觸發(fā)我們的回調(diào)函數(shù)// 主要是通過(guò)判斷一下當(dāng)前被focus的dom類(lèi)型
// document.activeElement.tagName
// tagName為輸入框的時(shí)候才算觸發(fā)鍵盤(pán)彈起
const activeDom = document.activeElement.tagName
if(!['INPUT', 'TEXTAREA'].includes(activeDom)) {
console.log('只有')
} -
當(dāng)有橫屏功能的時(shí)候,
resize也會(huì)被觸發(fā)
增加寬度是否有改變的判斷,沒(méi)有改變,才是真正的鍵盤(pán)彈起//初始化的時(shí)候獲取一次原始寬度
const originWidth = document.documentElement.clientWidth || document.body.clientWidth
//結(jié)合處理復(fù)選框、單選框的點(diǎn)擊也會(huì)導(dǎo)致`focusin` 和`focusout` 的觸發(fā)問(wèn)題的完整回調(diào)寫(xiě)法
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()
} -
怎么傳入回調(diào)函數(shù),靈活使用
v-指定: fn 傳入函數(shù),在指令里面通過(guò)執(zhí)行回調(diào)的時(shí)候傳出參數(shù),來(lái)區(qū)分是鍵盤(pán)彈起還是收起//綁定指令的同時(shí)傳入回調(diào)函數(shù)
v-keyboard:keyboardFn
methods: {
keyboardFn(val) {
//val true 鍵盤(pán)彈起 false 鍵盤(pán)收起
this.$toast(val ? '鍵盤(pán)彈起來(lái)了' : '鍵盤(pán)收起了')
}
}
建議
使用應(yīng)當(dāng)要注意銷(xiāo)毀,也需要盡量減少綁定指令的次數(shù),一般在form表單上綁定一個(gè),即可監(jiān)聽(tīng)這個(gè)表單下的所有輸入框是否觸發(fā)手機(jī)鍵盤(pán)喚起了
回復(fù)“加群”,一起學(xué)習(xí)進(jìn)步
