最近在做一个移动端 Web 项目,在首页底部是有一个类似于 APP 导航栏(以下称 FootNav),采用的 fixed 布局固定于底部。同时页面有一些 <input> 输入框(以下称 Input)。
当聚焦于 Input 时,在 iOS 预期效果是没问题,但是在杀千刀的 Android 上,页面高度发生变化,导致 FootNav 固定在手机键盘上面,同时 FootNav 也直接挡住了输入框,交互体验非常的糟糕。
烦死了...
先了解下背景,键盘的弹出收起,在 iOS 端与 Android 端的 WebView 中表现并非一致的。
由于我并没有过多的深入了解两者的差异表现,以上内容来自此处。
针对 Android 设备做处理就行了,iOS 无需处理。
处理方式:Input 聚焦隐藏 FootNav,失焦时再将其显示出来。(同理,修改布局方式也是一样的)
首先这种处理思路是没毛病的,但是...
某些机型、某些输入法,收起键盘并不会触发输入框的 blur 失焦事件,导致该方案直接流产。
监听页面高度的变化,利用这一点我们就可以处理 FootNav 的隐藏/显示了。
思路很简单:首先进入页面时,先记录窗口的原始高度。每当 Input 聚焦时,设置 window.onresize 函数,当窗口宽高发生改变时便会触发。
以 React 为例:
- class Home extends React.Component {
- constructor(props) {
- super(props)
- this.state = {
- showFootNav: true,
- initClientHeight: document.documentElement.clientHeight // 记录初始高度
- }
- }
-
- // 判断 Android 设备
- isAndroid() {
- const ua = navigator.userAgent.toLowerCase()
- return ua.includes('android') || ua.includes('linux')
- }
-
- // 监听窗口变化
- listenWindowResize() {
- let that = this
-
- if (this.isAndroid()) {
- window.onresize = () => {
- const { initClientHeight } = that.state
- const curClientHeight = document.documentElement.clientHeight // 当前页面高度
-
- if (curClientHeight < initClientHeight) {
- // 键盘弹出
- that.setState({ showFootNav: false })
- } else {
- // 键盘收起
- that.setState({ showFootNav: true }, () => {
- window.onresize = null // 清空 onresize
- })
- }
- }
- }
- }
-
- render() {
- const { showFootNav } = this.state
-
- // 以下 Input、FootNav 为自定义封装的组件
- return (
- <div>
- <Input onFocus={this.listenWindowResize.bind(this)} />
- {showFootNav ? <FootNav /> : null}
- </div>
- )
- }
- }
本文之外的一些兼容性问题,iOS 也有一些 bug 的,比如微信浏览器里收起键盘之后,页面不回弹,可参考文章。