【小贴士】虚拟键盘与fixed带给移动端的痛!

前言

今天来公司的主要目的就是研究虚拟键盘与fixed的问题,期间由于同事问起闭包与事件委托(阻止冒泡)相关问题,便穿插了一篇别的:css

【小贴士】工做中的”闭包“与事件委托的”阻止冒泡“,有兴趣的朋友能够去看看,由于首页只能放一篇,这个就略去了html

如今回到主要研究点,首先在移动端咱们点击文本框后会出现一个虚拟键盘, 虚拟键盘让页面可视区域获得了充分利用,可是也带来了一些问题node

问题源头

移动端虚拟键盘出现的条件是:文本框(文本类)得到焦点闭包

可是文本框得到焦点未必会弹出键盘!!!app

收起虚拟键盘的条件是:文本框失焦dom

PS:总而言之,咱们认为会出现或者消失虚拟键盘的时候均可能不工做ide

在移动设备上,若是文本框在上方,点击不会有什么问题:
在设备的最下面的话,就有所不一样了,整个块会上移,以将input区域显示出来post

这个时候几个棘手的问题就出现了:学习

① 虚拟键盘的出现对页面来讲是不可知的,这句话的理解是:没有键盘出现事件,没有办法获取键盘高度测试

② 键盘是“贴”在了viewport上,表面上不会对dom产生“任何”影响,可是这个时候一些定位元素的表现却变得“怪异”

好比:

能够看到,不管淘宝或者新浪,这个问题都存在,如今比较广泛的解决方案都是:移动端不采用fixed属性

因而咱们来看看是否有其它方案

iscroll是否能解决

其实这个方案在周四的时候我便测试过了,可是结果让人很遗憾

 

 

做为官方给出的例子,在虚拟键盘弹出来后,光标会乱跑,这个还能够接受,可是:

① 头部不见了

② 偶尔不能显示得到焦点的input

这两个问题就让人难以接受了,因而,咱们须要找到其余方案

解决方案

其实这个问题若是真要较真的话,我以为须要深刻研究两个知识点:

① viewport的原理

② 虚拟键盘的原理

就我手里现有资源来讲,两个知识点一个都不深刻,因此只能先从应用层面解决问题

应用层面解决方案

咱们想到这么一个场景,若是咱们能监控到键盘的行为,若是能的话,咱们即可以

① 键盘弹出时候将fixed元素设置为static

② 键盘消失时候将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);

根据测试结果来讲,是知足咱们的需求的,这里的header不会出问题,可是footer因为没有处理仍然会错位

 

因而这个问题彷佛被咱们修复了,可是你能够接受吗???这个方案有一个致命的恶心点!

不停的监控dom变化,浪费资源

那么这个问题可优化么?

彷佛是可优化的,可是依旧会带来不少问题,优化的入口与出口即是input标签的focus事件

至于其失焦相关的事件便不予关注了,由于可能由一个input跳到另外一个input

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);
  }
});

这样的话,貌似能让代码看上去舒服一点,可是其代价倒是全部input类标签都会多一个得到焦点事件,依旧使人痛惜

结语

今天的学习暂时到此,对于虚拟键盘的出现其实可能还有其余的问题,举一个例子来讲:

若是咱们点击按钮时候会出一个toast在中间,可是虚拟键盘恰好遮住了toast提示信息怎么办呢?这个问题与上述问题实际上是一致的

而后这个解决方案的可接受程度,以及其实际是否解决了问题又或者引发了其它问题就须要实际证实了

至于各位有什么好的解决方案,或者想法,能够讨论讨论哦!!!

好了,今天暂时到这里,咱们下次继续,若是有可能咱们会详细学习下viewport以及虚拟键盘相关

相关文章
相关标签/搜索