iScroll 4 不适用于表单 <select> 元素 iPhone Safari 和 Android 浏览器

Posted

技术标签:

【中文标题】iScroll 4 不适用于表单 <select> 元素 iPhone Safari 和 Android 浏览器【英文标题】:iScroll 4 not working with form <select> element iPhone Safari and Android browser 【发布时间】:2011-08-10 08:43:35 【问题描述】:

我正在使用这个 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>

&lt;select&gt; 不适用于 iPhone 和 android。当我点击选择框时没有任何反应。

我正在使用产生问题的 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>

我想this is a solution 但我不知道如何实现它。

【问题讨论】:

当我点击 我也在页面上使用iscroll4 您有重现问题的演示供我们查看吗? @JitendraVyas 我在一个 JQM 1.0 项目中遇到了这个问题,我发现你需要检查一下用户按下了什么样的元素节点。如果它是一个表单元素,杀死你的 iScroll 实例。否则(不是表单元素)检查该特定页面是否已经存在 iScroll 实例,如果是,则照常进行(正常行为),但如果没有,则初始化一个新的 iScroll 实例(以便您可以滚动)。这样做应该可以让您修复页面上的所有表单元素,而无需将事件监听器附加到给定页面上的每个表单元素或循环访问。 这已在 iScroll 5 中得到修复并且效果很好。早先将hack放在输入(或选择)字段上,您将无法通过触摸输入字段来滚动屏幕。这在 iScroll 5 中已经过分注意了。 【参考方案1】:

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

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

e.preventDefault();

如果您将其注释掉,您会注意到 select 标记再次起作用。

但将其注释掉意味着您已经破解了该库,这可能会破坏其他理想的 iScroll 功能。所以这里有一个更好的解决方法:

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

该代码将允许发生默认行为,而不会将事件传播到 iScroll 那里它搞砸了一切。

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

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

【讨论】:

顺便说一句,如果您想测试它或查看完整源代码,请在此处启动并运行它:edrooth.com/test @sym3tri - 感谢您的回答。它还会解决Android浏览器中的问题吗?而不是'Field10',我们不能使用'select',因为我想修复页面上的所有选择元素。 它也应该适用于 Android,但我不能肯定地说我没有 Android 手机。我在 iPhone 上测试了它,它可以工作。当然,您可以对所有选择标签执行相同的操作,只需调用 getElementsbyTagName('select') 并遍历它们。 顺便说一句,这应该可以在 Android b/c 中使用,我的代码所做的只是撤消 iScroll 对选择元素所做的操作。这两种环境都没有额外的代码。 iScroll 处理了它github.com/cubiq/iscroll/blob/master/examples/form-fields/…【参考方案2】:

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

启用对输入、选择和文本区域标签的关注

【讨论】:

升级iscroll会不会有问题?你在修改库,是不是很危险? 但这会导致 iScroll。点击并拉动任何表单元素时它不会滚动【参考方案3】:

终于为 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;

尝试了其他几种方法,才意识到这与iscroll添加的css有关。

【讨论】:

您需要将 OPTION 添加到 beforescrollstart 处理程序中测试的标记集 但这会导致 iScroll。点击并拉动任何表单元素时它不会滚动【参考方案4】:

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

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

     );

【讨论】:

我刚刚添加了您拥有的 onBeforeScrollStart 代码,效果很好。选定的答案有不必要的副作用。谢谢。【参考方案5】:

解决办法

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

【讨论】:

我在 Android 2.3.4 上使用了 comonitos 的解决方案,但它不起作用,我使用的是 iScroll 4.2 和 jQM 1.1.0,我也在插件 jquery.mobile 中尝试过这个解决方案。 iscrollview.js 但它也不起作用。 comonitos,您使用的是哪个版本的 jQM 和 iScroll?有人知道 Android 的解决方法吗? 它是 jquery.mobile-1.0a4 和 iScroll v4.0 Beta 4。a 可以向您发送我的库【参考方案6】:

解决方案的另一个代码示例。并感谢以前的 cmets! 使用 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);
                    );

【讨论】:

【参考方案7】:

换行,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 作品中

【讨论】:

【参考方案8】:

从这段代码开始。这个解决方案对我有用:

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

【讨论】:

【参考方案9】:

我迟到了,但我把我的解决方案留给你。

如果你使用 jQuery,你可以试试。

$('input, textarea, button, a, select').off('touchstart mousedown').on('touchstart mousedown', function(e) 
    e.stopPropagation();
);

【讨论】:

【参考方案10】:
  // 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 ... 花了一整天的时间调试和实施所有建议的解决方案无济于事......

【讨论】:

这个问题是关于 iScroll 4 - 你的解决方案是为版本 5 制定的。无论如何很高兴知道。【参考方案11】:

他任何人。

我知道你所有的答案,但我有新的方法可以提供。没有 java-script 或 drop iscroll 函数。

所有这些解决方案的最大问题是当您滚动输入元素时,页面上没有滚动。当你只输入一两个输入时并不重要,但是当页面是一个表单时,滚动页面就有很大的问题。

我提供的解决方案是将输入包装在标签标签中,或者使用指向输入的指针制作标签标签。然后使用绝对定位和 z-index 制作输入上方的标签。当您触摸标签时,您会关注输入。

请举例

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;

您也可以通过这种方式将输入的标签侧放在输入的绝对位置并将其放入标签区域

100% 工作,检查一下

【讨论】:

【参考方案12】:

当 -webkit-transform:translate3d 应用于具有选择框或密码框 [1] 的容器时,Android 存在错误。激活这些元素的方框区域会移动,而不是您认为它们会在的位置。此外,密码框绘制在不同的位置,因此看起来您有两个输入元素而不是一个。

我在 AppMobi 工作,我们开发了一个工具包库来修复这些问题。我们已经实现了自定义选择框小部件和密码输入字段的替换。请在下面查看。

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

[1] 我认为评论的作者在谈论这个错误https://bugs.webkit.org/show_bug.cgi?id=50552

【讨论】:

【参考方案13】:

我玩游戏有点晚了,但如果有人仍然感兴趣,我会使用 @bastien 的 approach 并对其进行一些调整以使其在 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);



基本上,您需要做的就是在用户选择表单元素时销毁您的 iScroll 实例,但在他们实际开始滚动之前 (onBeforeScrollStart) 并且如果用户单击具有自定义属性 @987654323 的元素内的任何其他内容@,他们可以像往常一样使用 iScroll 滚动。

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

【讨论】:

【参考方案14】:

这是一个对我有用的非常简单的解决方法。我注意到在 Android 浏览器中,在初始页面加载时我无法单击选择框,但我能够单击用于搜索的文本输入字段。然后我注意到,在我点击文本输入字段后,它会识别出我点击了一个选择框。所以我所做的只是将这个添加到我用来加载搜索页面的 javascript 函数中......

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

所以当搜索页面被加载时,它会自动关注文本输入字段但不会弹出键盘,这正是我想要的。抱歉,我的示例无法公开访问,但希望这仍然可以帮助某人。

【讨论】:

【参考方案15】:

试试这个解决方案 if (e.target.nodeName.toLowerCase() == "select" || e.target.tagName.toLowerCase() == 'input' || e.target.tagName.toLowerCase() == 'textarea') 返回;

【讨论】:

【参考方案16】:

怎么样,这对我有用!:

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

【讨论】:

【参考方案17】:

即使您在 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

你不能在“-webkit-transform”css样式的div的输入元素中输入汉字。 iscroll 4 将“-webkit-transform”与滚动条 div 一起应用。

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

【讨论】:

【参考方案18】:

Android 浏览器错误是由于 Android 内部的 WebKit 版本非常旧,甚至在 Android 4.3 内部也是如此。错误的根本原因 - iScroll 发送回浏览器的点击事件的错误处理(删除 preventDefault 只是停止发送此点击事件) Android Chrome 浏览器没有这个 bug,因为它内部升级了 WebKit 库。

等待 Google 升级 Android WebKit。

【讨论】:

【参考方案19】:

检查这个。这解决了我的问题

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

在我选择的选项中

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

【讨论】:

以上是关于iScroll 4 不适用于表单 <select> 元素 iPhone Safari 和 Android 浏览器的主要内容,如果未能解决你的问题,请参考以下文章

Jquery验证不适用于选择

为啥条件渲染不适用于 vuejs 中的表单输入

Angular 4 表单验证器 - minLength 和 maxLength 不适用于字段类型号

Django模板标签切片不适用于表单切片

Bootstrap 多选不适用于剔除绑定

JQuery Validate 不适用于 Bootstrap Carousel 中的表单