您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~
问题描述
在native
中拉起键盘再收回,滚动列表实际距离发生变化,被键盘一起弹上去了(我这里大约是400px的样子)
这是初始页面:
当我聚焦页面中某个Input
后,再失去焦点,页面变成了这样:
可以看到页面被弹上去了,再次重复步骤页面会继续弹上去,排查了一下发现是在IOS
中的问题。
解决方案
我这里想到的一个比较好的方案是监听弹起键盘
和收起键盘
两个事件,在弹起时记录被破坏的页面scrollY
,收起时恢复。
记录弹起时的页面scrollY
挺简单的,直接这样:
window.addEventListener('focusin', () => {
console.log('弹起前高度:', window.scrollY);
}, false)
这样思路就很简单了,代码实现一下:
const focusScrollHeight = useRef<number>(0);
useEffect(() => {
window.addEventListener('focusin', focusIn, false);
window.addEventListener('focusout', focusOut, false);
return () => {
window.removeEventListener('focusin', focusIn, false);
window.removeEventListener('focusout', focusOut, false);
};
}, []);
const focusIn = () => {
focusScrollHeight.current = window.scrollY;
};
const focusOut = (e) => {
window.scrollTo(0, focusScrollHeight.current);
};
把这段代码放在出现问题的页面里,发现页面会不稳定的回弹到顶部,排查下来应该是antd
的组件触发了收起键盘的事件,所以考虑用类名定位的方案来搞定,同时我们直接封装成一个hook
,在出现问题的页面中直接使用,就像这样:
useResetScrollY.ts
/**
* @description: 声明式hook,在页面声明即可自动归位手机端键盘弹起撑开的高度
* @param {string} listenerClassList 监听的类名
* @return {*}
*/
const useResetScrollY = (listenerClassList: string[]) => {
const focusScrollHeight = useRef<number>(0);
useEffect(() => {
window.addEventListener('focusin', focusIn, false);
window.addEventListener('focusout', focusOut, false);
return () => {
window.removeEventListener('focusin', focusIn, false);
window.removeEventListener('focusout', focusOut, false);
};
}, []);
const focusIn = () => {
focusScrollHeight.current = window.scrollY;
};
const focusOut = (e) => {
const classNameList: string[] = Array.from(e?.target?.classList);
if (classNameList?.some((item: string) => listenerClassList?.includes(item))) {
window.scrollTo(0, focusScrollHeight.current);
}
};
};
export { useResetScrollY };
这里入参我们给出在页面中需要被监听的组件类名,一般来说都是Input
、Textarea
这类表单组件,然后在这个页面我使用的是antd
的Input
组件,所以使用是这样的:
const Page = () => {
// ...
if(isIos) {
useResetScrollY(['adm-input-element']);
}
// ...
}
这样子在hook
内部触发事件时只需要判断事件对象的classList
与入参classList
是否存在公共项的情况,就会触发键盘副作用归位的行为。
写在后面
这是笔者在业务中遇到的一个问题,简单总结记录,如果对于这种情况有更好的方案也欢迎留言讨论~
您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~