iScroll 4不支持表单<select>元素iPhone Safari和Android浏览器

我正在使用这个HTML代码:

<form action="#" method="post"> <fieldset> <label class="desc" id="title10" for="Field10"> How many children do you have? </label> <select id="Field10" name="Field10" class="field select large" tabindex="5"> <option value="0" selected="selected">0 </option> <option value="1">1 </option> <option value="2">2 </option> <option value="3">3 </option> <option value="4">4 </option> <option value="5">5 </option> <option value="6">6 </option> <option value="7">7 </option> <option value="8">8 </option> <option value="9">9 </option> </select> <input type="submit" value="Send message" /> </fieldset> </form> 

iPhone和Android上的<select>不起作用。 当我点击select框时,什么也没有发生。

我正在使用正在创build问题的iScroll 4。

 <script type="application/javascript" src="iscroll-lite.js"></script> <script type="text/javascript"> var myScroll; function loaded() { myScroll = new iScroll('wrapper'); } document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); document.addEventListener('DOMContentLoaded', loaded, false); </script> 

我认为这是一个解决scheme,但我不知道如何实现它。

问题是,iScroll取消了你的select标签的默认行为(如果你问我,不是很好的实现)。

这发生在行195上的_start()函数中:

 e.preventDefault(); 

如果你评论这一点,你会注意到select标签再次工作。

但是评论它意味着你已经入侵了可能会破坏其他所需的iScrollfunction的库。 所以这是一个更好的解决方法:

 var selectField = document.getElementById('Field10'); selectField.addEventListener('touchstart' /*'mousedown'*/, function(e) { e.stopPropagation(); }, false); 

该代码将允许发生默认行为,而不会将事件传播到iScroll,从而将所有事情都搞砸了。

由于您的JS不在任何类似jQuery的onReady()事件中,所以您必须确保将这些代码放在select元素定义的HTML 之后

请注意,对于移动设备,该事件是touchstart ,但是对于您的PC浏览器,它将被mousedown

我在Android上的iScroll 4.1.9上有同样的问题,我只是取代了95(在我的版本)行:

 onBeforeScrollStart: function (e) { e.preventDefault(); }, 

通过:

 onBeforeScrollStart: function (e) {var nodeType = e.explicitOriginalTarget ? e.explicitOriginalTarget.nodeName.toLowerCase():(e.target ? e.target.nodeName.toLowerCase():''); if(nodeType !='select' && nodeType !='option' && nodeType !='input' && nodeType!='textarea') e.preventDefault(); }, 

这使得重点在input,select和textarea标签

最后解决这个Android的。 最后在iscroll.js中修改了几行

以下是我们如何初始化iScroll。

 // code from https://github.com/cubiq/iscroll/blob/master/examples/form-fields/index.html // don't preventDefault for form controls _menuScroll = new iScroll('menu_wrapper',{ useTransform: false, onBeforeScrollStart: function (e) { var target = e.target; while (target.nodeType != 1) target = target.parentNode; if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') e.preventDefault(); } }); 

onBeforeScrollStart是允许控件的默认行为发生的。 Android浏览器似乎与useTransform有问题,所以转到false。

最后,当useTransform为false时,需要排除一些额外的iscroll代码:

 // iscroll.js v4.1.9 // line 216: if (that.options.useTransform) bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:-' + vendor + '-transform;-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);-' + vendor + '-transition-duration:0;-' + vendor + '-transform:' + trnOpen + '0,0' + trnClose; // line 295: if (that.options.useTransform) that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = trnOpen + (dir == 'h' ? pos + 'px,0' : '0,' + pos + 'px') + trnClose; 

尝试了几个其他的方法,才意识到它必须做的CSS添加CSS。

这是解决scheme

 /* on page add this after all scripts */ <script type="text/javascript"> var myScroll; function loaded() { myScroll = new iScroll('wrapper'); } document.addEventListener('DOMContentLoaded', function(){ setTimeout(loaded,500);}, false); </script> /* attach a script for fix */ $(document).ready(function(){ var my_select = document.getElementsByTagName('select'); for (var i=0; i<my_select.length; i++) { my_select[i].addEventListener('touchstart' /*'mousedown'*/, function(e) { myScroll.destroy(); setTimeout(function(){myScroll = new iScroll('wrapper');},500); }, false); } /*if you have input problems */ var input = document.getElementById('input'); if (input) { input.addEventListener('touchstart' /*'mousedown'*/, function(e) { e.stopPropagation(); }, false); } }); 

另一个代码示例解决scheme。 并感谢以前的评论! 使用jquery!

后:

 $(document).ready(function() { document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); document.addEventListener('DOMContentLoaded', setTimeout(function () { loaded(); }, 200), false); }); 

在加载函数中

 function loaded() { var allSelects = $('select'); allSelects.each(function(index, item) { item.addEventListener('touchstart' /*'mousedown'*/, function(e) { e.stopPropagation(); }, false); }); } 

replace行, onBeforeScrollStart: function (e) { e.preventDefault(); }, onBeforeScrollStart: function (e) { e.preventDefault(); },

通过

 onBeforeScrollStart: function (e) { var nodeType = e.explicitOriginalTarget ? e.explicitOriginalTarget.nodeName.toLowerCase():(e.target ? e.target.nodeName.toLowerCase():''); if(nodeType !='select' && nodeType !='option' && nodeType !='input' && nodeType!='textarea') { e.preventDefault(); } }, 

iScroll.js Works中

从这个代码开始。 这个解决scheme为我工作:

 <script type="text/javascript"> var myScroll; function iScrollLoad() { myScroll = new iScroll('wrapper'); enableFormsInIscroll(); } function enableFormsInIscroll(){ [].slice.call(document.querySelectorAll('input, select, button, textarea')).forEach(function(el){ el.addEventListener(('ontouchstart' in window)?'touchstart':'mousedown', function(e){ e.stopPropagation(); }) }) } document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); document.addEventListener('DOMContentLoaded', function () { setTimeout(iScrollLoad, 200); }, false); </script> 

我知道迟到了,但对某些人可能有帮助,

在pageshow事件中写下面的代码,但要确保div id不一样。

这是因为iscroller阻止了元素的默认行为

  $('#yourpage').bind('pageshow',function (event, ui) { var myScroll; if (this.id in myScroll) { myScroll[this.id].refresh(); }else{ myScroll[this.id] = new iScroll('wrapper', { //wrapper is div id checkDOMChanges: true, onBeforeScrollStart: function (e) { var target = e.target; while (target.nodeType != 1) target =target.parentNode; if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA'){ e.preventDefault(); } } }); } document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); }); 

我迟到了,但我离开你我的解决scheme。

如果你正在使用jQuery,你可以尝试。

 $('input, textarea, button, a, select').off('touchstart mousedown').on('touchstart mousedown', function(e) { e.stopPropagation(); }); 
  // Setup myScroll myScroll = new IScroll('#wrapper', { scrollX: horizontalSwipe, scrollY: !horizontalSwipe, momentum: false, snap: document.querySelectorAll('#scroller .slide'), snapSpeed: 400, bounceEasing: 'back', keyBindings: true, click: true }); 

对我来说,我只需要在最后一行添加click:true …花了整整一天的时间debugging和实施所有build议的解决scheme,无济于事…

他任何人。

我知道所有的答案,但我有新的方式提供。 没有java脚本或放弃iscroll函数。

所有这个解决scheme的大问题是当你滚动input的元素,你没有在页面上滚动。 当你只做一个或两个input是不是真的很重要,但当页面是一个窗体,你有很大的问题,滚动页面。

我提供的解决scheme是将input包装在标签标签中,或者将标签标签用于指向input的指针。 然后用绝对定位和z-索引input上方的标签。 当您触摸标签时,您将注意力集中在input上。

请举例

HTML

 <fieldset> <label> <input type="text" /> </label> </fieldset> 

CSS

 fieldset {position:relative;z-index:20;} label {position:relative;z-index:initial;} input {position:relative;z-index:-1;} 

你也可以这样把input的标签面和input的绝对位置放到标签区域

正在100%工作,检查它

当-webkit-transform:translate3d被应用到具有select框或密码框的容器时,Android有一个错误[1]。 激活这些元素的盒装区域移动,而不是你认为他们会的地方。 此外,密码框画在不同的位置,所以看起来你有两个input元素,而不是一个。

我在AppMobi工作,我们已经开发了一个工具包库,有修复这些。 我们已经实现了自定义select框小部件和密码input字段的替代。 看看下面。

https://github.com/imaffett/AppMobi.toolkit

[1]我觉得评论的作者正在谈论这个bug https://bugs.webkit.org/show_bug.cgi?id=50552

我对游戏有点迟,但是如果有人还有兴趣的话,我采取了@ bastien的方法,并调整了一下,让它在Android上运行。 我正在使用JQM与我的实施。

基本上我所做的是:

 function scrollMe(element) { var contentID = $wrapper.get(0).id; var scroller = elm.find('[data-iscroll="scroller"]').get(0); if (scroller) { var iscroll = new iScroll(contentID, { hScroll : false, vScroll : true, hScrollbar : false, vScrollbar : true, fixedScrollbar : true, fadeScrollbar : false, hideScrollbar : false, bounce : true, momentum : true, lockDirection : true, useTransition : true, //the preceding options and their values do not have any to do with the fix //THE FIX: onBeforeScrollStart: function(e) { var nodeType = e.explicitOriginalTarget ? e.explicitOriginalTarget.nodeName.toLowerCase() : (e.target ? e.target.nodeName.toLowerCase():''); //get element node type if(nodeType !='select' && nodeType !='option' && nodeType !='input' && nodeType!='textarea') e.preventDefault(); //be have normally if clicked element is not a select, option, input, or textarea. else if (iscroll != null) { //makes sure there is an instance to destory iscroll.destroy(); iscroll = null; //when the user clicks on a form element, my previously instanced iscroll element is destroyed } }, onScrollStart: function(e) { if (iscroll == null) { //check to see if iscroll instance was previously destoryed var elm = $.mobile.activePage; //gets current active page var scrollIt = setTimeout( function(){ scrollMe(elm) }, 0 ); } //recursively call function that re-instances iscroll element, as long as the user doesn't click on a form element } }); elm.data("iscroll-plugin", iscroll); } } 

基本上所有你需要做的是当用户select一个表单元素,但在他们真的开始滚动(onBeforeScrollStart)之前,并且如果用户用自定义属性data-iscroll="scroller" ,他们可以像往常一样使用iScroll滚动。

 <div data-role="page" id="pageNameHere" data-iscroll="enable"> 

这是一个非常简单的解决scheme,为我工作。 我注意到在Android浏览器,在初始页面加载我不能点击一个select框,但我可以点击我用于search的文本input字段。 然后我注意到,当我点击文本input字段后,它会识别我点击一个select框。 所以我所做的只是添加到我用来加载search页面的JavaScript函数…

 $('#search').focus(); 

所以当search页面被加载时,它会自动对焦在文本input字段,但不popup键盘,这正是我想要的。 对不起,我的例子是不公开的,但希望这仍然可以帮助别人。

如果(e.target.nodeName.toLowerCase()==“select”|| e.target.tagName.toLowerCase()=='input'|| e.target.tagName.toLowerCase()=='textarea '){
返回; }

那么,这对我有用!

 $('input, select').on('touchstart', function(e) { e.stopPropagation(); }); 

即使您排除了onBeforeScrollStart()中的表单元素,android 2.2 / 2.3 browser / webview中还存在另一个bug:

https://www.html5dev-software.intel.com/viewtopic.php?f=26&t=1278 https://github.com/01org/appframework/issues/104

你不能用“-webkit-transform”css风格在div的input元素中input中文字符。 iscroll 4将“-webkit-transform”应用于滚动div。

解决方法是将表单字段保存在滚动条外的绝对div中。

Android浏览器bug是Android内部很老版本的WebKit的结果,甚至在Android 4.3内部。 iScroll发送回浏览器的click事件error handling的根本原因(去掉preventDefault只是停止发送这个点击事件)Android Chrome浏览器是免费的,因为它已经升级了WebKit库。

正在等待Google的Android WebKit升级。