IOS 浏览器软键盘的拉起与收缩、微信 IOS 浏览器底部导航条的显示与隐藏,很容易致使页面布局错位(相对窗体的绝对定位元素):git
window
对象的 resize
事件,而 IOS 不会window
对象的 resize
事件,而 Android 中没有底部导航条window
对象的 resize
事件无论是 IOS 浏览器软键盘的拉起与收缩,仍是微信 IOS 浏览器底部导航条的显示与隐藏,都是改变的 window 窗体的大小。github
微信 IOS 浏览器底部导航条的显示与隐藏跟软键盘的拉起与收缩是差很少的,但微信 IOS 浏览器底部导航条还有一个很大的特色:浏览器
在单页面应用(SPA)中,当路由发生变化时,底部导航条会一会儿就显示,而这很难肯定是先渲染了页面仍是先显示了底部导航条,
这也很容易致使元素布局错位。微信
新建 watch-keyboard.js
脚本,引入到页面中。函数
当页面中键盘弹起时,body
会有 keyboard-active
class,能够根据这个隐藏一些元素。布局
import {isIos} from '../utils'; import debounce from 'lodash/debounce'; // 初始高度 const winHeight = window.innerHeight; // 判断是否是弹起了软键盘 const judgeDistance = 200; if (!isIos) { window.addEventListener( 'resize', debounce(() => { if (window.innerHeight < winHeight - judgeDistance) { // 键盘弹起 document.body.classList.add('keyboard-active'); } else { document.body.classList.remove('keyboard-active'); } }, 300), !1 ); } else { // IOS 软键盘的弹起与收缩不会触发 `window` 对象的 `resize` 事件,用定时器实现 // 保证可以滚动 document.body.style.minHeight = (winHeight + 2) + 'px'; // 上两次高度记录 let secondLastWinHeight = winHeight; // 上一次高度记录 let lastWinHeight = winHeight; setInterval(() => { const newWinHeight = window.innerHeight; // 变化结束 if (secondLastWinHeight !== lastWinHeight && lastWinHeight === newWinHeight) { if (newWinHeight < winHeight - judgeDistance) { // 键盘弹起 document.body.classList.add('keyboard-active'); } else { document.body.classList.remove('keyboard-active'); // window 须要滚动一下,让页面刷新一下,不然弹框会出现错位的问题 window.scrollTo(0, window.scrollY ? window.scrollY - 1 : 1); } } secondLastWinHeight = lastWinHeight; lastWinHeight = newWinHeight; }, 300); // 能够根据须要调整间隔时间(越小越精确) }
当软键盘弹起时,又点击了一个按钮,而后显示弹框(如:从底部向上弹出)的时候,这个时候就须要等待软键盘收起以后,IOS 刷新屏幕以后,再显示弹框。code
新建 wait-for-stable-win-height.js
脚本,引入到页面中。对象
import { isIos } from '../utils'; /** * 等待 window 高度不变了以后执行一个回调函数 * * @param onComplete 完成的回调 * @param delay 延迟多少时间再判断 * @param interval 定时器间隔时间 */ export default ({ onComplete, delay = 200, interval = 50 }) => { setTimeout(() => { let winHeight = window.innerHeight; const timer = setInterval(() => { const newWinHeight = window.innerHeight; if (winHeight === newWinHeight) { clearInterval(timer); if (onComplete) { if (!isIos) { setTimeout(() => { onComplete(); }, 100); return; } // window 须要滚动一下,让页面刷新一下,不然弹框会出现错位的问题 window.scrollTo(0, window.scrollY ? window.scrollY - 1 : 1); setTimeout(() => { onComplete(); }, 200); } } else { winHeight = newWinHeight; } }, interval); }, delay); };
更多博客,查看 https://github.com/senntyou/blogsblog
做者:深予之 (@senntyou)事件
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)