移动端虚拟键盘与fixed

#前言
前段日子,运营一哥们跟我说,我们之前上线的xx商城,移动端在部分苹果手机上打字的时候会出现很诡异的事情。我研究了几天,觉得需要贴出来备忘一下。


#问题描述
当出现虚拟键盘时,文本(类)框获得焦点时,原来的fixed就失去效果了。移动端有一个footer是用fixed定位的。下图标红的部分:
免税店
但是如果弹出虚拟键盘就会失去效果,原图我现在没有,就在网上照了一张,大家凑合着看:
弹出虚拟键盘

#解决之路
本来我以为所有手机都会出现这种问题,但是经过多方排查,只有ios系统7.2的版本会出现这个问题。其他android和ios其他版本均不会出现。之后查了些资料,最后还是解决了问题。<鼓掌>虽然有点geek。

在移动设备上,如果文本框在上方,点击不会有什么问题;在设备的最下面的话,就有所不同了,整个块会上移,以将input区域显示出来;
首先以下有些问题是我不可处理的:

  1. 虚拟键盘的出现对页面来说是不可知的,没有键盘出现事件,没有办法获取键盘高度
  2. 键盘是浮在了viewport上,表面上不会对dom产生“任何”影响,但是这个时候一些定位元素的表现却变得诡异

一般大公司的处理方法是:移动端不采用fixed属性。在设计环节就杜绝问题的出现。但是这显然不适合我们,产品都已经上线了啊。
然后我起初的构思是从根源着手,深入研究两个知识点:

  1. viewport的原理
  2. ios虚拟键盘的原理

就我手里现有资源和时间来说,都不能完成,所以只能先从应用层面解决问题。
应用层面解决方案
我们想到这么一个场景,如果我们能监控到键盘的行为,如果能的话,我们便可以
1.键盘弹出时候将fixed元素设置为static2.键盘消失时候将fixed元素设置为fixed

这个方案好恶心啊,我当时想到的时候也被这个方案吓了一跳,但是或许这是现阶段最好的解决方案了。
我的做法就是:监控dom变化!
监控键盘
监控的方式其实筛选下来也不过两种:

  • 时钟setInterval不停监控
  • 系统级别的监控,比如键盘出现时候通知window一个事件,但是很遗憾现在还没有这个事件,但是这个事件等于
    input类元素获取焦点 == 弹出虚拟键盘input类元素失去焦点 == 收起虚拟键盘

但是我们前面已经说过,上面的原则不一定可靠,所以该种方案也未必可靠了
基于系统监控这点,我们还可以监控resize事件或者scroll事件,但是经过我的测试,setInterval表现比较好
于是,我们简单写一段代码,可靠是否满足需求:

window.alert = function (msg) {
$('body').append('<div>' + msg + '</div>')
};
function fixedWatch(el) {
if(document.activeElement.nodeName == 'INPUT'){
el.css('position', 'static');
} else {
el.css('position', 'fixed');
}
}
setInterval(function () {
fixedWatch($('#headerview header'));
}, 500);

这个问题似乎被我们修复了,但这个方案有一个致命的恶心点!不停的监控dom变化,浪费资源。
后来我又优化了一下,只有获取焦点的时候才加个定时器,代码感觉好很多了。

setTimeout(function () {
$('#dl_app img').hide();
}, 100);
window.alert = function (msg) {
$('body').append('<div>' + msg + '</div>')
};
window.res = null;
var i = 0;
function fixedWatch(el) {
alert(i++);
if(document.activeElement.nodeName == 'INPUT'){
el.css('position', 'static');
} else {
el.css('position', 'fixed');
if(window.res ) {
clearInterval(window.res );
window.res = null;
}
}
}
$('input').focus(function () {
if(!window.res) {
fixedWatch($('#headerview header'));
window.res = setInterval(function () {
fixedWatch($('#headerview header'));
}, 500);
}
});

#结束
移动端开发毕竟是个新兴行业,规范和方法都不是很健全,在这个时代,我们每一个人都是开拓者。用各式各样的方法去解决处理问题,提升自己。谨写下这个问题,愿与君共勉。
「Stay Hungry . Stay Foolish.」