简体   繁体   English

iScroll 4无法使用表单<select>元素iPhone Safari和Android浏览器

[英]iScroll 4 not working with form <select> element iPhone Safari and Android browser

I'm using this HTML code: 我正在使用这个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>

<select> is not working on iPhone and Android. <select>无法在iPhone和Android上运行。 When I tap on the selectbox nothing happens. 当我点击选择框时没有任何反应。

I'm using iScroll 4 which is creating the problem. 我正在使用创建问题的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>

I think this is a solution but I don't know how to implement it. 我认为这是一个解决方案,但我不知道如何实现它。

The problem is that iScroll cancels the default behavior of your select tag (Not a very good implementation if you ask me). 问题是iScroll取消了select标签的默认行为(如果你问我,这不是一个很好的实现)。

This occurs in the _start() function on line 195: 这发生在第195行的_start()函数中:

e.preventDefault();

If you comment that out you'll notice the select tag works again. 如果你发表评论,你会发现select标签再次起作用。

But commenting it out means you've hacked the library which might break other desirable iScroll functionality. 但是评论它意味着你已经破解了可能破坏其他理想的iScroll功能的库。 So here's a better workaround: 所以这是一个更好的解决方法:

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

That code will allow the default behavior to occur, without propagating the event to iScroll where it screws everything up. 该代码将允许发生默认行为,而不会将事件传播到iScroll,它会将所有内容都搞砸。

Since your JS is not inside any jQuery-like onReady() event, you'll have to make sure to you put this code AFTER the HTML where your select elements are defined. 由于您的JS不在任何类似jQuery的onReady()事件中,因此您必须确保将此代码放在定义了select元素的HTML 之后

Note that for mobile devices the event is touchstart , but for your PC browser it will be mousedown 请注意,对于移动设备,事件是touchstart ,但对于您的PC浏览器,它将被mousedown

I had the same issue on the iScroll 4.1.9 on android, I just replaced the line 95 (on my version) : 我在Android上的iScroll 4.1.9上遇到了同样的问题,我刚刚更换了第95行(在我的版本上):

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

by : 通过:

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

that enable focus on input, select and textarea tags 这使得能够专注于输入,选择和textarea标签

Finally fixed this for Android. 最后为Android修复此问题。 Ended up modifying a couple of lines in iscroll.js 结束了在iscroll.js中修改几行

Here's how we initialize iScroll. 以下是我们初始化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();
    }
});

The onBeforeScrollStart is what allows the controls' default behaviors to take place. onBeforeScrollStart允许控件的默认行为发生。 Android browser seems to have problem with useTransform, so turn to false. Android浏览器似乎有useTransform的问题,所以转向false。

Finally, some additional iscroll code needed to be excluded when useTransform is 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;

Tried several other methods before realizing that it had to do with the css that iscroll adds. 在意识到它与iscroll添加的css有关之前,尝试了其他几种方法。

I Know am late,but it might be helpful for some one, 我知道已经很晚了,但对某些人来说可能会有帮助,

write the following code in pageshow event,but be sure that div ids not same. 在pageshow事件中编写以下代码,但请确保div ID不相同。

it is because, iscroller prevents the default behaviors of elements 这是因为,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);

     });

Here is the solution 这是解决方案

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

Replacing line, onBeforeScrollStart: function (e) { e.preventDefault(); }, 替换行, onBeforeScrollStart: function (e) { e.preventDefault(); }, onBeforeScrollStart: function (e) { e.preventDefault(); },

By 通过

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

In iScroll.js Works iScroll.js Works中

Start with this code. 从这段代码开始。 This solution worked for me: 这个解决方案对我有用:

<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>

another code example for solution. 解决方案的另一个代码示例 and thanks for previous comments! 并感谢以前的评论! Using Jquery! 使用Jquery!

After: 后:

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

    document.addEventListener('DOMContentLoaded', setTimeout(function () { loaded(); }, 200), false);
});

in loaded function 在加载功能

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

I'm late but I leave you my solution. 我迟到了,但我留给你解决方案。

If your are using jQuery you can try that. 如果你正在使用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
  });

For me, I just need to add click: true on the last line... Spent the whole day debugging and implementing all the suggested solutions to no avail... 对我来说,我只需要在最后一行添加click:true ...花了一整天调试并实现所有建议的解决方案无济于事...

he anyone. 他是谁

i know's about all your answer's but i have new way to offer. 我知道你的所有答案,但我有新的方式提供。 without java-script or drop iscroll functions. 没有java脚本或drop iscroll函数。

the big problems with all this solution is when you scroll on input's element you have no scroll on the page. 所有这些解决方案的主要问题是当您滚动输入元素时,页面上没有滚动。 when you make just one or two input's isn't really matter but when the page is a form you have big problem to scroll the page. 当你只做一两个输入时并不重要但是当页面是一个表单时你滚动页面有很大的问题。

the solution i offering is to wrap the input in label tag or make the label tag with for pointer to the input. 我提供的解决方案是将输入包装在label标签中,或者将label标签用于指向输入的指针。 then make with absolute positioning and z-index the label above the input. 然后用绝对定位和z-index制作输入上方的标签。 when you touch on the label you focus the input. 当您触摸标签时,您可以聚焦输入。

and example please 请举例

HTML HTML

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

CSS CSS

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

you can also in this way put the label side of the input and with position absolute of the input put that into the label area 您也可以通过这种方式将输入的标签面和输入的绝对位置放入标签区域

is working in 100%, check it 正在100%工作,检查它

I'm a bit late to the game, but if anyone is still interested, I took @bastien's approach and tweaked it a bit to get it to work on Android. 我有点迟到了,但如果有人仍然感兴趣,我采取了@ bastien的方法,并调整了一下,让它在Android上运行。 I'm using JQM with my implementation. 我正在使用JQM实现我的实现。

Basically what I did was: 基本上我做的是:

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

}

Basically all you need to do is destroy your iScroll instance when a form element is selected by the user, but before they actually start scrolling (onBeforeScrollStart) and if the user clicks on anything else within the element with the custom attribute data-iscroll="scroller" , they can scroll using iScroll as usual. 基本上,当用户选择表单元素时,但在实际开始滚动(onBeforeScrollStart)之前以及用户使用自定义属性data-iscroll="scroller"点击元素中的任何其他内容时,您需要做的就是销毁iScroll实例。 data-iscroll="scroller" ,他们可以像往常一样使用iScroll滚动。

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

try this solution if (e.target.nodeName.toLowerCase() == "select" || e.target.tagName.toLowerCase() == 'input' || e.target.tagName.toLowerCase() == 'textarea') { 尝试这个解决方案if(e.target.nodeName.toLowerCase()==“select”|| e.target.tagName.toLowerCase()=='input'|| e.target.tagName.toLowerCase()=='textarea '){
return; 返回; } }

What about, that works for me!: 那对我有用的东西!:

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

Even if you've excluded form elements in onBeforeScrollStart(), there is another bug in android 2.2/2.3 browser/webview: 即使你在onBeforeScrollStart()中排除了表单元素,android 2.2 / 2.3浏览器/ webview中还有另一个错误:

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

You can't input chinese characters in input elements in the div with "-webkit-transform" css style. 您不能使用“-webkit-transform”css样式在div的输入元素中输入中文字符。 The iscroll 4 applied the "-webkit-transform" with the scroller div. iscroll 4将“-webkit-transform”应用于滚动条div。

The solution is to keep form fields in a absolute div out of the scroller. 解决方案是将表单字段保留在滚动条的绝对div中。

Android browser bug is result of very old version of WebKit inside Android, even inside Android 4.3. Android浏览器错误是Android内部非常旧版本的WebKit的结果,甚至在Android 4.3中也是如此。 The root cause of bug - wrong processing of the click event that iScroll sends back to the browser (removing preventDefault just stops sending this click event) The Android Chrome browser is free from this bug because it has upgraded WebKit library inside. 错误的根本原因 - 错误处理iScroll发送回浏览器的点击事件(删除preventDefault只是停止发送此点击事件)Android Chrome浏览器没有此错误,因为它已经升级了WebKit库。

Waiting for Android WebKit upgrade from Google. 正在等待从谷歌升级Android WebKit。

Check this. 检查一下。 This fixed my issue 这解决了我的问题

https://github.com/cubiq/iscroll/issues/576 https://github.com/cubiq/iscroll/issues/576

In option I have selected 在我选择的选项中

click:false, preventDefaultException:{tagName:/.*/}

There is a bug with Android when -webkit-transform:translate3d is applied to a container that has a select box or password box[1]. 当-webkit-transform:translate3d应用于具有选择框或密码框[1]的容器时,Android存在一个错误。 The boxed area to activate those elements move, and are not where you think they'd be. 用于激活这些元素的盒装区域会移动,而不是您认为它们的位置。 Additionally, password boxes paint in a different location, so it appears that you have two input elements instead of one. 此外,密码框在不同的位置绘制,因此看起来您有两个输入元素而不是一个。

I work at AppMobi and we have developed a toolkit library that has fixes for these. 我在AppMobi工作,我们开发了一个工具包库,修复了这些。 We've implemented custom select box widgets and a replacement for the password input field. 我们已经实现了自定义选择框小部件并替换了密码输入字段。 Check it out below. 请在下面查看。

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

[1] I think the author of the comment is talking about this bug https://bugs.webkit.org/show_bug.cgi?id=50552 [1]我认为评论的作者正在谈论这个错误https://bugs.webkit.org/show_bug.cgi?id=50552

Here's a really easy fix that worked for me. 这是一个非常简单的解决方案,对我有用。 I noticed in the Android browsers that on initial page load I could not click on a select box but I was able to click on a text input field that I was using for Search. 我注意到在Android浏览器中,在初始页面加载时我无法单击选择框,但我能够单击我用于搜索的文本输入字段。 Then I noticed that after I clicked on the text input field, it would recognize me clicking a select box. 然后我注意到,在我点击文本输入字段后,它会识别我单击一个选择框。 So all I did was add this to the javascript function I was using to load the Search page... 所以我所做的只是将其添加到我用来加载搜索页面的javascript函数中...

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

So when the search page gets loaded, it automatically focuses on the text input field but does not pop up the keyboard, which is exactly what I wanted. 因此,当搜索页面加载时,它会自动聚焦于文本输入字段,但不会弹出键盘,这正是我想要的。 Sorry my example is not publicly accessible, but hopefully this can still help somebody. 对不起我的例子不公开,但希望这仍然可以帮助某人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM