H5软键盘弹出和收起在安卓和ios以及不同浏览器之间存在不同的表现形式,网上也找不到更全面的解决方案,为此自己研究出能兼容主流浏览器的解决方案。
问题
在做手机评论功能的交互时,必须要通过监听软键盘弹出和收起来实现,比如实现“点击回复评论弹出键盘,收起键盘就取消回复操作,输入框清空输入值”。
在研究过程中发现有以下几个问题:
- 安卓非谷歌浏览器高度会变化,横屏时不会收起键盘
- 安卓最新谷歌浏览器高度不会变化(页面上推),横屏时会收起键盘,但会触发resize事件
- 安卓收起键盘后input可能并未失焦
- 有些浏览器可能会多次触发resize事件
- ios收起键盘页面会上滚
完整的代码放在最下面。
使用方式
当页面只有一个输入框的情况下使用
<script setup>
import keyboard from "./keyboard";
const vKeyboard = keyboard;
const keyboardFn = val => {
console.log(val ? "弹出键盘" : "收起键盘")
};
</script>
<template>
<input v-keyboard="keyboardFn" />
</template>
完整代码
const isIOS = /iphone|ipad|ipod/.test(navigator.userAgent.toLocaleLowerCase());
const originHeight =
document.documentElement.clientHeight || document.body.clientHeight;
let scrollTop = 0;
const keyBoard = {
mounted(el, binding, vnode) {
const isFocus = ref(false);
const isResiz = ref(0);
const isChange = ref(false);
const isHeight = ref(false);
el.resizeFn = () => {
const resizeHeight =
document.documentElement.clientHeight || document.body.clientHeight;
if (resizeHeight < originHeight) {
isChange.value = true;
isHeight.value = true;
} else {
isHeight.value = false;
}
if (isFocus.value) isResiz.value++;
};
if (!isIOS) {
window.addEventListener("resize", el.resizeFn);
// 第1种情况处理方式
watch(isHeight, () => {
if (isChange.value && isFocus.value && !isHeight.value) {
binding.value(false);
}
});
// 第2种情况处理方式
watch(isResiz, () => {
if (!isChange.value && isFocus.value && isResiz.value > 1) {
binding.value(false);
}
});
}
el.handlerFocusin = () => {
if (!isIOS) {
isFocus.value = true;
binding.value(true);
} else {
binding.value(true);
scrollTop = document.documentElement.scrollTop;
}
};
el.handlerFocusout = () => {
if (!isIOS) {
// 先失焦后后收起键盘的情况处理
if (isFocus.value) {
binding.value(false);
}
isFocus.value = false;
isChange.value = false;
isHeight.value = false;
isResiz.value = 0;
} else {
binding.value(false);
// 处理 iOS 收起软键盘页面会上滚问题
setTimeout(() => window.scrollTo({ top: scrollTop }), 50);
}
};
el.addEventListener("focusin", el.handlerFocusin);
el.addEventListener("focusout", el.handlerFocusout);
},
unmounted(el) {
window.removeEventListener("resize", el.resizeFn);
el.removeEventListener("focusin", el.handlerFocusin);
el.removeEventListener("focusout", el.handlerFocusout);
}
};
export default keyBoard;