一、问题由来css
作h5 已经有很长一段时间了,如今作的工做h5比pc上的更多,曾经解决pc端IE各个版本的兼容性也是伤透脑筋,原觉得h5的会更好,却不知,还有更头疼的问题,当设计师要设计一个聊天窗口,把输入框定位在最底部,这是再常见不过的问题了吧,举例:html
上图就是我最近作的一个功能,原觉得是很简单的一个定位功能,可是没想到牛逼的测试竟然用各类iphone,各类安卓,各类浏览器(qq浏览器、safari、opera等浏览器),各类输入法(系统自带、搜狗输入法),测出来一大堆问题,最后通过千辛万苦,终于作到了能大体兼容。linux
二、初步解决android
1)、结构布局于第一次解决浏览器
1 //1部分css 2 .header { 3 width: 100%; 4 height: 40px; 5 } 6 //2部分 7 .body { 8 width: 100%; 9 overflow: auto; 10 } 11 //3部分 12 .footer { 13 width: 100%; 14 height: 30px;position: fixed; bottom:0;left:0;right:0; 15 }
1 <div class="header" id="header">会话问诊</div> 2 <div class="body" id="body"></div> 3 <div class="footer" id="footer"> 4 <input type="text" id="input"> 5 </div>
1 $('.body').css('height', $(window).height() - 39); 2 $('#input').on('focus', function () { 3 setTimeout(function () { 4 window.scrollTo(0, 1000000); 5 }, 200); 6 });
这种布局方法就让中间".body"中的内容在".body"中滚动,对整个html中的body产生了1px的滚动,此处滚动的目的是为了执行"window.scrollTo(0, 1000000);",通过测试,若body没有产生滚动,则这个方法是不会执行的。iphone
相信不少人都会以 以上的方法解决input在弹出键盘时候的问题,当键盘弹出来后,就让滚动条一直往下面滚直到滚动到最下面,没错,这种措施以后能保证大部分的正常,可是在safari浏览器中就出现了问题,因为safari浏览器下部有一块布局
图中是safari浏览器自带的一块标签,当使用以上滚动时,你会发现,他虽然是滚动上去了,可是也会出现一块空白,没错,至关于给你的感受是滚动上去过多,那么此时,也会被测试打回,是否是感受很伤心无助,(safari浏览器把下面那块看成了body的东西,他本身实现了一块,把咱们的html内容装在了他本身实现的容器里面)测试
2)、进一步解决优化
通过大量的比较与测试,我发现了一个问题,safari下面的自带输入法根本不用处理,键盘依然能够正常弹出与收起。(ps:safari浏览器没有特别的判断,所以此处判断过于复杂,若有更好的判断,请留言,谢谢!此处之因此判断safari浏览器并非判断QQ浏览器,是由于测试了opera浏览器的展现等跟QQ浏览器同样,所以此处就判断safari浏览器)this
1 $('input').on('focus', function () { var agent = navigator.userAgent.toLowerCase(); 2 setTimeout(function () { 3 if (agent.indexOf('safari') != -1 && agent.indexOf('mqqbrowser') == -1 4 && agent.indexOf('coast') == -1 && agent.indexOf('android') == -1 5 && agent.indexOf('linux') == -1 && agent.indexOf('firefox') == -1) {//safari浏览器 6 } else {//其余浏览器 7 window.scrollTo(0, 1000000); 8 } 9 }, 200); 10 });
3)、再次优化与解决
通过以上几步骤,原觉得天衣无缝的解决方案,能够达到很好的兼容了,但是意外又发生了,测试们用了搜狗输入法来作测试,问题又来了,苹果手机自带的输入法的实现是把body挤上去,搜狗则是在获得focus以后,直接弹出的一块遮罩层,这就致使了问题,此时咱们的输入框被挡在了输入法以后,所以又增长了下面的判断与处理,
1 $('input').on('focus', function () { 2 setTimeout(function () { 3 if (agent.indexOf('safari') != -1 && agent.indexOf('mqqbrowser') == -1 4 && agent.indexOf('coast') == -1 && agent.indexOf('android') == -1 5 && agent.indexOf('linux') == -1 && agent.indexOf('firefox') == -1) {//safari浏览器 6 if(scope.$txtWrap.offset().top-winobj.scrollTop() > document.body.offsetHeight/2) { //说明软键盘遮盖页面 7 window.scrollTo(0, winobj.height() - 270); 8 } 9 } else {//其余浏览器 10 window.scrollTo(0, 1000000); 11 } 12 }, 200); 13 });
三、解决
通过几回测试,看似几乎没问题,最后又在iphone5上面的QQ浏览器中用搜狗输入法又测试出了问题,它在第一次点击当input获取到第一次focus事件的时候,window执行了scrollTo方法,第二次,他再也不执行,不难发现,系统是觉得已经滚动到了下方,所以便再也不执行,那么我又增长了一个事件
$('input').on('blur', function () { window.scrollTo(0, 0); });
终于大功告成,基本上解决了如今广泛浏览器中大部分搜狗和自带输入法对模拟fix的input定位问题。
总结最后解决js为:
1 $('input').on('focus', function () { 2 var agent = navigator.userAgent.toLowerCase(); 3 setTimeout(function () { 4 if (agent.indexOf('safari') != -1 && agent.indexOf('mqqbrowser') == -1 5 && agent.indexOf('coast') == -1 && agent.indexOf('android') == -1 6 && agent.indexOf('linux') == -1 && agent.indexOf('firefox') == -1) {//safari浏览器 7 if(scope.$txtWrap.offset().top-winobj.scrollTop() > document.body.offsetHeight/2) { //说明软键盘遮盖页面 8 window.scrollTo(0, winobj.height() - 270); 9 } 10 } else {//其余浏览器 11 window.scrollTo(0, 1000000); 12 } 13 }, 200); 14 }); 15 16 $('input').on('blur', function () { 17 var agent = navigator.userAgent.toLowerCase(); 18 setTimeout(function () { 19 if (!(agent.indexOf('safari') != -1 && agent.indexOf('mqqbrowser') == -1 20 && agent.indexOf('coast') == -1 && agent.indexOf('android') == -1 21 && agent.indexOf('linux') == -1 && agent.indexOf('firefox') == -1)) {//非safari浏览器 22 window.scrollTo(0, 0); 23 } 24 }, 0); 25 });
重中之重,必定要让body产生滚动,否则以上方法依然没法解决。
最近同事又测出了个人方案对某些手机的不兼容性,因此他给出了另外一个解决方案,经测试已经达到了几乎全部手机的兼容,下面提供给你们:
inputFocus: function (e) { var winobj = $(window), scope = this, agent = navigator.userAgent.toLowerCase(); setTimeout(function () { if (agent.indexOf('safari') != -1 && agent.indexOf('mqqbrowser') == -1 && agent.indexOf('coast') == -1 && agent.indexOf('android') == -1 && agent.indexOf('linux') == -1 && agent.indexOf('firefox') == -1) {//safra浏览器 window.scrollTo(0, 1000000);//先滚动到最底部,再用scrollY获得当前的值,必须延迟 不然拿到的就是1000000 setTimeout(function(){ window.scrollTo(0, window.scrollY - 45);//45像素 全部浏览器都是这么高 }, 50) } else {//其余浏览器 window.scrollTo(0, 1000000); // window.scrollTo(0, ++this.scrollNum); } }, 200); },
这是我解决这个问题的过程与实践,若你们有更好的思路,或者发现我这个方式依然没法解决某些问题,请在留言区提出,谢谢!