当前位置: 首页 > Web前端 > HTML

通过focusout事件解决IOS键盘收起时界面不归位的问题

时间:2023-04-02 19:22:16 HTML

使用focusout事件解决IOS键盘收起界面不回原位的问题问题及症状详述如下:页面结构有问题的页面是一个表单结构。即类似于一个div下有4个输入表单的结构,用于用户填写邮寄信息。类似:

截图如下:当键盘弹出时,页面自动上移当用户在手机上输入联系电话时,会弹出iPhone键盘,此时为了让用户在iPhone上看到电话输入框,整个页面会上移为一个整体(否则键盘会盖住手机输入框)。此时,页面顶部实际上是距离我们视口的一部分距离(我们看到一排输入框从界面上消失了)。键盘收回时无法恢复页面。但是,当用户完成输入并关闭键盘时,虽然键盘收回了,但是页面位置并不会恢复。问题分析其实这是由于IOS收回键盘时页面滚动出视口的部分没有脱落造成的。这时,用户可以用手指将页面向后拖动。但毕竟体验不好。为了解决这个问题,我们可以在用户光标离开输入框时调用window.scrollTo(0,0)来滚动页面对齐视口顶部,从而达到页面归位的效果。所以现在的问题是给表单中的所有4个输入框都添加blur事件,然后在handler中调用window.scrollTo。但是无论是通过Vue的@blur添加,还是通过DOM操作,添加4个事件监听器都不是很优雅。很自然地,我们想到了使用事件代理。事件代理,也就是我们把事件监听器放在最上面的元素上;然后定义一个等待触发的inputBlur函数。
结果发现我们的事件监听器无法触发。原因是输入框的blur事件不能冒泡。不能冒泡的解决办法查询后发现规范中focus和blur这两个DOM事件是不能冒泡的。与之类似的还有另外两个事件focusin和focusout可以冒泡。网上有文章提到focusin和focusout是IE浏览器支持的一种DOM事件。其实我们看了MDN文档发现这两个事件已经成为了DOM3规范的一个标准,能够支持的浏览器数量还是挺多的。所以,果断通过这两个事件解决问题,我们改为focusout
然后,实现我们的事件处理器:inputBlur(e){//首先判断触发事件的目标元素是否为input输入框。我们只关注输入框的行为。如果(e&&e.target&&e.target.tagName&&e.target.tagName.toLowerCase()==='input'){window.scrollTo(0,0);}},至此,我们的问题就解决了,当你从输入框输入内容,然后点击键盘关闭键盘时,效果符合我们的预期。但是在手机端测试后发现,当我们直接从手机输入框切换到姓名输入框时,页面会抖动。我们继续分析。解决抖动问题其实两个输入框切换时出现抖动的原因也很简单。因为当我们在上面两个输入框之间切换时,页面会先触发电话输入框的blur事件,然后再触发姓名输入框的focus事件。在这种情况下,我们的window.scrollTo(0,0)会在blur时被触发,导致页面向下滚动一点,然后name输入框获得焦点,键盘继续弹出---这就导致了页面再次向上移动。事实上,在两个输入框之间切换时,我们不需要在第一个输入框模糊时触发window.scrollTo行为。所以我们修改一下我们的代码,在输入框切换发生的时候,切断第一个输入框的行为。这里我们使用setTimeout来解决:
inputBlur(e){//首先判断触发事件的目标元素是否为输入框,我们只关注输入框的行为。if(e&&e.target&&e.target.tagName&&e.target.tagName.toLowerCase()==='input'){//输入框失去焦点,IOS键盘滚动部分推出该页面应恢复。即滚动页面到窗口顶部对齐console.log('settimer')this.timer=setTimeout(()=>{console.log('timertriggered')window.scrollTo(0,0);},0)}},inputFocus(e){//如果获得焦点,去掉上一个输入框的定时器if(e&&e.target&&e.target.tagName&&e.target.tagName.toLowerCase()==='输入'){clearTimeout(this.timer);}}结尾