如何在移动Safari中打开虚拟键盘时阻止固定导航移动?

我知道移动Safari浏览器在固定的元素周围有很多的错误,但是大部分时间我都设法正确地工作,直到我在底部的固定导航中添加了一个非常需要的文本input。 现在,当用户关注文本input元素并出现虚拟键盘时,我的导航一直固定在页面的底部,在页面中间跳到一个非常奇怪的地方。

在这里输入图像说明

我会添加一些我的代码到这个职位,但我不知道从哪里开始。 该导航固定在底部,并定位在左侧和底部0,宽度为100%。 从那里,我不知道发生了什么,我只能认为这是一个移动的Safari浏览器的错误。

它也似乎失去了它的位置固定,并成为相对的,只有当文本input元素的重点和虚拟键盘打开。

http://dansajin.com/2012/12/07/fix-position-fixed/这是提出的解决scheme之一。; 似乎值得一试。

简而言之:将任何inputfocus fixed元素设置为position:absolute ,当元素blur红色时将其重置

 .header { position: fixed; } .footer { position: fixed; } .fixfixed .header, .fixfixed .footer { position: absolute; } 

 if ('ontouchstart' in window) { /* cache dom references */ var $body = $('body'); /* bind events */ $(document) .on('focus', 'input', function() { $body.addClass('fixfixed'); }) .on('blur', 'input', function() { $body.removeClass('fixfixed'); }); } 

顶部的解决scheme是一些方法去解决这个问题,但我认为增加额外的CSS类或使用moderniz我们正在复杂的事情。

如果你想要一个更简单的解决scheme,这里是一个非现代化的 非额外的CSS,但纯粹的jQuery解决scheme,并在每个设备和浏览器上工作,我在我的所有项目

 if ('ontouchstart' in window) { $(document).on('focus', 'textarea,input,select', function() { $('.navbar.navbar-fixed-top').css('position', 'absolute'); }).on('blur', 'textarea,input,select', function() { $('.navbar.navbar-fixed-top').css('position', ''); }); } 

我有一个类似的问题,但我发现一个解决方法,通过将下面的css类添加到input焦点上的body元素,然后再将其重新删除:

 .u-oh { overflow: hidden; height: 100%; width: 100%; position: fixed; } 

从sylowgreen所做的事情来看,关键是要固定body进入input 。 从而:

 $("#myInput").on("focus", function () { $("body").css("position", "fixed"); }); $("#myInput").on("blur", function () { $("body").css("position", "static"); }); 

像这样添加javascript:

 $(function() { var $body; if ('ontouchstart' in window) { $body = $("body"); document.addEventListener('focusin', function() { return $body.addClass("fixfixed"); }); return document.addEventListener('focusout', function() { $body.removeClass("fixfixed"); return setTimeout(function() { return $(window).scrollLeft(0); }, 20); }); } }); 

并像这样添加类:

 .fixfixed header{ position: absolute; } 

你可以参考这篇文章: http : //dansajin.com/2012/12/07/fix-position-fixed/

我真的很喜欢上面的解决scheme。 我把它打包成一个小的jQuery插件,所以我可以:

  • 设置哪个父类获得该类
  • 设置适用于哪些元素(不要忘记“textarea”和“select”)。
  • 设置父类名称
  • 让它被链接
  • 允许多次使用它

代码示例:

 $.fn.mobileFix = function (options) { var $parent = $(this), $fixedElements = $(options.fixedElements); $(document) .on('focus', options.inputElements, function(e) { $parent.addClass(options.addClass); }) .on('blur', options.inputElements, function(e) { $parent.removeClass(options.addClass); // Fix for some scenarios where you need to start scrolling setTimeout(function() { $(document).scrollTop($(document).scrollTop()) }, 1); }); return this; // Allowing chaining }; // Only on touch devices if (Modernizr.touch) { $("body").mobileFix({ // Pass parent to apply to inputElements: "input,textarea,select", // Pass activation child elements addClass: "fixfixed" // Pass class name }); } 

我使用这个jQuery脚本:

 var focus = 0; var yourInput = $(".yourInputClass"); yourInput.focusin(function(){ if(!focus) { yourInput.blur(); $("html, body").scrollTop($(document).height()); focus = 1; } if(focus) { yourInput.focus(); focus = 0; } }); 

为我完美的作品。

focusinfocusout事件似乎更适合于这个问题,而不是focusblur事件,因为前一个泡沫直到根本元素。 在SO上看到这个答案 。

我个人使用AngularJS,所以我这样实现:

 $window.document.body.addEventListener('focusin', function(event) { var element = event.target; var tagName = element.tagName.toLowerCase(); if(!$rootScope.inputOverlay && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) { $rootScope.$apply(function() { $rootScope.inputOverlay = true; }); } }); $window.document.body.addEventListener('focusout', function() { if($rootScope.inputOverlay) { $rootScope.$apply(function() { $rootScope.inputOverlay = false; }); } }); 

注意:如果这是移动版Safari,我有条件地运行这个脚本。

我在我的导航栏上放置了一个ng-class属性:

 <div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}"> 

使用下面的CSS:

 .navbar-absolute { position: absolute !important; } 

你可以在这里阅读更多关于focusin 信息

testing这一个。 有用。 我只是testing它。

 $(document).on('focus','input', function() { setTimeout(function() { $('#footer1').css('position', 'absolute'); $('#header1').css('position', 'absolute'); }, 0); }); $(document).on('blur','input', function() { setTimeout(function() { $('#footer1').css('position', 'fixed'); $('#header1').css('position', 'fixed'); }, 800); }); 

这些解决scheme都没有为我工作,因为我的DOM是复杂的,我有dynamic的无限滚动页面,所以我必须创build自己的。

背景:我使用一个固定的标题和一个下面的元素,一旦用户向下滚动,就会粘在它下面。 这个元素有一个searchinput字段。 另外,在向前和向后滚动时添加了dynamic页面。

问题:在iOS中,只要用户点击了固定元素中的input,浏览器就会一直滚动到页面的顶部。 这不仅造成了不良的行为,还触发了页面顶部的dynamic页面添加。

预期的解决scheme:当用户点击sticky元素中的input时,在iOS中不滚动(根本没有)。

解:

  /*Returns a function, that, as long as it continues to be invoked, will not be triggered. The function will be called after it stops being called for N milliseconds. If `immediate` is passed, trigger the function on the leading edge, instead of the trailing.*/ function debounce(func, wait, immediate) { var timeout; return function () { var context = this, args = arguments; var later = function () { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; function is_iOS() { var iDevices = [ 'iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod' ]; while (iDevices.length) { if (navigator.platform === iDevices.pop()) { return true; } } return false; } $(document).on("scrollstop", debounce(function () { //console.log("Stopped scrolling!"); if (is_iOS()) { var yScrollPos = $(document).scrollTop(); if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px) $('#searchBarDiv').css('position', 'absolute'); $('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header } else { $('#searchBarDiv').css('position', 'inherit'); } } },250,true)); $(document).on("scrollstart", debounce(function () { //console.log("Started scrolling!"); if (is_iOS()) { var yScrollPos = $(document).scrollTop(); if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px) $('#searchBarDiv').css('position', 'fixed'); $('#searchBarDiv').css('width', '100%'); $('#searchBarDiv').css('top', '50px'); //50 for fixed header } } },250,true)); 

要求: jQuery mobile是startsroll和stopscroll函数工作所必需的。

反弹是为了消除由粘滞元素产生的任何滞后。

在iOS10中testing

丹萨津提出的解决scheme,我没有什么运气。 自从他写博客文章以来,这个bug可能已经发生了变化,但是在iOS 7.1上,当input模糊后,当位置变回原来的位置时,即使延迟到软件键盘完全隐藏,也会出现bug。 我遇到的解决scheme涉及到等待touchstart事件而不是blur事件,因为固定元素在页面滚动时总是回退到合适的位置。

 if (Modernizr.touch) { var $el, focused; $el = $('body'); focused = false; $(document).on('focus', 'input, textarea, select', function() { focused = true; $el.addClass('u-fixedFix'); }).on('touchstart', 'input, textarea, select', function() { // always execute this function after the `focus` handler: setTimeout(function() { if (focused) { return $el.removeClass('u-fixedFix'); } }, 1); }); } 

HTH