在日常的聊天和使用手機(jī)的時(shí)候不知道大家有沒有這種感受,有時(shí)候手機(jī)鍵盤會(huì)自動(dòng)的彈出之后有自己收起來,于是圍繞著這個(gè)問題,今天小編和大家講講有關(guān)于:“如何實(shí)現(xiàn)手機(jī)鍵盤彈出收起?”這個(gè)問題的解決方法和相關(guān)內(nèi)容分享給大家!
前言:前端時(shí)間也是應(yīng)項(xiàng)目的需求開始了h5移動(dòng)端的折騰之旅,在目前中臺(tái)的基礎(chǔ)上擴(kuò)展了兩個(gè)ToC移動(dòng)端項(xiàng)目,下面就是在h5移動(dòng)端表單頁面鍵盤彈出收起兼容性的一些總結(jié)。
在 h5 項(xiàng)目中,我們會(huì)經(jīng)常遇到一些表單頁面,在輸入框獲取焦點(diǎn)時(shí),會(huì)自動(dòng)觸發(fā)鍵盤彈起,而鍵盤彈出在 IOS 與 Android 的 webview 中表現(xiàn)并非一致,同時(shí)當(dāng)我們主動(dòng)觸發(fā)鍵盤收起時(shí)也同樣存在差異化。
鍵盤彈出
- IOS:IOS系統(tǒng) 的鍵盤處在窗口的最上層,當(dāng)鍵盤彈起時(shí),webview 的高度 height 并沒有改變,只是 scrollTop 發(fā)生變化,頁面可以滾動(dòng)。且頁面可以滾動(dòng)的最大限度為彈出的鍵盤的高度,而只有鍵盤彈出時(shí)頁面恰好也滾動(dòng)到最底部時(shí),scrollTop 的變化值為鍵盤的高度,其他情況下則無法獲取。這就導(dǎo)致在 IOS 情況下難以獲取鍵盤的真實(shí)高度。
- Android: 在Android系統(tǒng)中,鍵盤也是處在窗口的最上層,鍵盤彈起時(shí),如果輸入框在靠近底部的話,就會(huì)被鍵盤擋住,只有你輸入的時(shí)候輸入框才會(huì)滾動(dòng)到可視化區(qū)域。
鍵盤收起
- IOS:觸發(fā)鍵盤上的按鈕收起鍵盤或者輸入框以外的頁面區(qū)域時(shí),輸入框會(huì)失去焦點(diǎn),因此會(huì)觸發(fā)輸入框的 blur 事件;當(dāng)鍵盤收起時(shí),頁面底部會(huì)出現(xiàn)一個(gè)空白區(qū)域,頁面會(huì)被頂起。
- Android: 觸發(fā)鍵盤上的按鈕收起鍵盤時(shí),輸入框并不會(huì)失去焦點(diǎn),因此不會(huì)觸發(fā)頁面的 blur 事件;觸發(fā)輸入框以外的區(qū)域時(shí),輸入框會(huì)失去焦點(diǎn),觸發(fā)輸入框的 blur 事件。
期望的結(jié)果
針對(duì)不同系統(tǒng)觸發(fā)鍵盤彈出收起時(shí)的差異化,我們希望功能流暢的同時(shí),盡量保持用戶體驗(yàn)的一致性。
對(duì)癥下藥
上面我們理清了目前市面上兩大主要系統(tǒng)的差異性,接下來就需對(duì)癥下藥了。
在 h5 中目前沒有接口可以直接監(jiān)聽鍵盤事件,但我們可以通過分析鍵盤彈出、收起的觸發(fā)過程及表現(xiàn)形式,來判斷鍵盤是彈出還是收起的狀態(tài)。
- 鍵盤彈出:輸入框獲取焦點(diǎn)時(shí)會(huì)自動(dòng)觸發(fā)鍵盤的彈起動(dòng)作,因此,我們可以監(jiān)聽 focusin 事件,在里面實(shí)現(xiàn)鍵盤彈出后所需的頁面邏輯。
- 鍵盤收起:當(dāng)觸發(fā)其他頁面區(qū)域收起鍵盤時(shí),我們可以監(jiān)聽 focusout 事件,在里面實(shí)現(xiàn)鍵盤收起后所需的頁面邏輯。而在通過鍵盤按鈕收起鍵盤時(shí)在 ios 與 android 端存在差異化表現(xiàn),下面具體分析:
- IOS:觸發(fā)了 focusout 事件,仍然通過該辦法監(jiān)聽。
- Android:沒有觸發(fā) focusout 事件。在 android 中,鍵盤的狀態(tài)切換(彈出、收起)不僅和輸入框關(guān)聯(lián),同時(shí)還會(huì)影響到 webview 高度的變化,那我們就可以通過監(jiān)聽 webview height 的變化來判斷鍵盤是否收起。
系統(tǒng)判斷
在實(shí)踐中我們可以通過 userAgent 來判斷目前的系統(tǒng):
const ua = window.navigator.userAgent.toLocaleLowerCase();
const isIOS = /iphone|ipad|ipod/.test(ua);
const isAndroid = /android/.test(ua);
IOS 處理
let isReset = true; //是否歸位
this.focusinHandler = () => {
isReset = false; //聚焦時(shí)鍵盤彈出,焦點(diǎn)在輸入框之間切換時(shí),會(huì)先觸發(fā)上一個(gè)輸入框的失焦事件,再觸發(fā)下一個(gè)輸入框的聚焦事件
};
this.focusoutHandler = () => {
isReset = true;
setTimeout(() => {
//當(dāng)焦點(diǎn)在彈出層的輸入框之間切換時(shí)先不歸位
if (isReset) {
window.scroll(0, 0); //確定延時(shí)后沒有聚焦下一元素,是由收起鍵盤引起的失焦,則強(qiáng)制讓頁面歸位
}
}, 30);
};
document.body.addEventListener('focusin', this.focusinHandler);
document.body.addEventListener('focusout', this.focusoutHandler);
Android 處理
const originHeight = document.documentElement.clientHeight || document.body.clientHeight;
this.resizeHandler = () => {
const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
const activeElement = document.activeElement;
if (resizeHeight < originHeight) {
// 鍵盤彈起后邏輯
if (activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA")) {
setTimeout(()=>{
activeElement.scrollIntoView({ block: 'center' });//焦點(diǎn)元素滾到可視區(qū)域的問題
},0)
}
} else {
// 鍵盤收起后邏輯
}
};
window.addEventListener('resize', this.resizeHandler);
react 封裝
在 react 中我們可以寫一個(gè)類裝飾器來修飾表單組件。
類裝飾器:類裝飾器在類聲明之前被聲明(緊靠著類聲明)。 類裝飾器應(yīng)用于類構(gòu)造函數(shù),可以用來監(jiān)視,修改或替換類定義。
// keyboard.tsx
/*
* @Description: 鍵盤處理裝飾器
* @Author: hzzly
* @LastEditors: hzzly
* @Date: 2020-01-09 09:36:40
* @LastEditTime: 2020-01-10 12:08:47
*/
import React, { Component } from 'react';
const keyboard = () => (WrappedComponent: any) =>
class HOC extends Component {
focusinHandler: (() => void) | undefined;
focusoutHandler: (() => void) | undefined;
resizeHandler: (() => void) | undefined;
componentDidMount() {
const ua = window.navigator.userAgent.toLocaleLowerCase();
const isIOS = /iphone|ipad|ipod/.test(ua);
const isAndroid = /android/.test(ua);
if (isIOS) {
// 上面 IOS 處理
...
}
if (isAndroid) {
// 上面 Android 處理
...
}
}
componentWillUnmount() {
if (this.focusinHandler && this.focusoutHandler) {
document.body.removeEventListener('focusin', this.focusinHandler);
document.body.removeEventListener('focusout', this.focusoutHandler);
}
if (this.resizeHandler) {
document.body.removeEventListener('resize', this.resizeHandler);
}
}
render() {
return <WrappedComponent {...this.props} />;
}
};
export default keyboard;
使用:
// PersonForm.tsx
@keyboard()
class PersonForm extends PureComponent<{}, {}> {
// 業(yè)務(wù)邏輯
...
}
export default PersonForm;
那么以上就是我們對(duì)于:“如何實(shí)現(xiàn)手機(jī)鍵盤彈出收起?”這個(gè)問題的相關(guān)內(nèi)容分享和解決方法總結(jié)了,當(dāng)然如果大家對(duì)于html5這方面有所興趣的話我們都可以在W3Cschool進(jìn)行學(xué)習(xí)和了解。