这个问题,其实在前端是个老生常谈的问题。
在生产环境中,我们是嵌入到 app 中使用的 H5 降级页面,在去哪儿和携程的 app 中的 webview 容器,表现不一致
携程的 app 表现比较正常,和一般浏览器表现类似,但是去哪儿,有点奇葩。键盘弹起来之后,页面高度依旧不变,着实费解。
最终的解决方案其实是在携程中使用 scrollIntoViewIfNeeded
在比较奇葩的去哪儿使用监听 focus,在底部加 padding 的做法。之所以不使用定位,是因为,键盘高度我不确定。所以我给 padding,这样白色的区域即使大一点也可以接受。不至于出现浮层和键盘中间断层。
具体的代码截取了部分。其实,主要是个思路。代码自己实现更好,因为涉及到调试,不自己写的话,心里也没底。
我是使用 ts+react实现,另外,我认为尽量不要使用定位来实现,因为你不知道哪个 webview 就会出现幺蛾子。当然了,定位也解决不了键盘遮挡的问题
!核心函数,计算 dom 位置
// 计算需要提升的元素 : dom的位置
const movePanel = (enevt: string) => {
if (judgeDeviceType.isIOS) {
const dom = codeRef.current.closest(".css-3pxmmn");
if (dom) {
console.log("enevt", enevt);
// 这里是区分 去哪儿端,去哪儿的 webview 容器,比较奇葩,scrollIntoView 不生效,
// 虽然页面被推上去了,但是页面高度不变,所以特殊处理
if (window.location.href.indexOf("qunar") > -1) {
if (enevt === "blur") {
return setTimeout(() => {
dom.style.paddingBottom = 0;
}, 0);
}
if (enevt === "focus") {
return setTimeout(() => {
dom.style.paddingBottom = "380px";
}, 300);
}
if (enevt === "click") {
return setTimeout(() => {
dom.style.paddingBottom = "380px";
}, 0);
}
}
return setTimeout(() => {
dom.scrollIntoViewIfNeeded(true);
}, 300);
}
}
};
首次展示的时候,触发一次 focus
// 首次展示的时候,调用一次 focus
// codeRef.current 代表需要 focus 的 input 元素
useEffect(() => {
let moveTimer: any = null;
if (visiable && codeRef.current) {
codeRef.current.focus();
moveTimer = movePanel("focus");
}
return () => {
clearTimeout(moveTimer);
};
}, [visiable, codeRef.current]);
操作浮层上的 input 元素,触发重新定位函数
// 注册 focus, click, blur 事件
// drawerRef.current 代表需要 改变定位的浮层容器
useEffect(() => {
let moveTimer: any = null;
if (
drawerRef &&
drawerRef.current &&
codeRef &&
codeRef.current &&
!isBindListener
) {
codeRef.current.addEventListener("focus", () => {
moveTimer = movePanel("focus");
});
codeRef.current.addEventListener("click", () => {
moveTimer = movePanel("click");
// drawerRef.current.style.bottom = "240px";
});
codeRef.current.addEventListener("blur", () => {
moveTimer = movePanel("blur");
});
}
isBindListener = true;
return () => {
clearTimeout(moveTimer);
};
}, [
drawerRef,
drawerRef.current,
codeRef,
codeRef.current,
isBindListener,
]);