web-dev-qa-db-fra.com

iScroll 4 ne fonctionne pas avec l'élément <select> de formulaire iPhone Safari et le navigateur Android

J'utilise ce 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> ne fonctionne pas sur iPhone et Android. Lorsque je tape sur la zone de sélection, rien ne se passe.

J'utilise iScroll 4 qui crée le problème.

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

Je pense ceci est une solution mais je ne sais pas comment la mettre en œuvre.

26
Jitendra Vyas

Le problème est qu'iScroll annule le comportement par défaut de votre balise select (ce n'est pas une très bonne implémentation si vous me le demandez).

Cela se produit dans la fonction _start() à la ligne 195:

e.preventDefault();

Si vous le commentez, vous remarquerez que la balise select fonctionne à nouveau.

Mais commenter cela signifie que vous avez piraté la bibliothèque, ce qui pourrait casser d'autres fonctionnalités souhaitables d'iScroll. Alors voici une meilleure solution de contournement:

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

Ce code permettra au comportement par défaut de se produire, sans propager l'événement à iScroll où il visse tout. 

Étant donné que votre JS ne fait partie d'aucun événement onReady() de type jQuery, vous devez vous assurer de bien mettre ce codeAPR&EGRAVE;Sle code HTML où vos éléments select sont définis. 

Notez que pour les appareils mobiles l'événement est touchstart, mais pour le navigateur de votre PC, il sera mousedown

46
sym3tri

J'ai eu le même problème sur l'iScroll 4.1.9 sur Android, je viens de remplacer la ligne 95 (sur ma version):

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

par :

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

qui permettent de se concentrer sur les balises input, select et textarea

10
bastien

Enfin résolu cela pour Android. Nous avons fini par modifier quelques lignes dans iscroll.js

Voici comment initialiser 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();
    }
});

Le onBeforeScrollStart est ce qui permet aux comportements par défaut des contrôles d'avoir lieu. Le navigateur Android semble avoir un problème avec useTransform, donc passez à false. 

Enfin, certains codes iscroll supplémentaires devaient être exclus lorsque useTransform est false:

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

J'ai essayé plusieurs autres méthodes avant de me rendre compte que cela avait à voir avec les CSS que iscroll ajoute.

6
deCastongrene

Je sais que je suis en retard, mais cela pourrait être utile pour quelqu'un,

écrivez le code suivant dans l'événement pageshow, mais assurez-vous que les identifiants div ne sont pas identiques.

c'est parce que, iscroller empêche les comportements par défaut des éléments

 $('#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);

     });
4
Mallikarjun

Voici la 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);
            }    
        });
3
comonitos

Commencez avec ce code. Cette solution a fonctionné pour moi:

<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>
2
Joe L.

Remplacement de la ligne, onBeforeScrollStart: function (e) { e.preventDefault(); },

Par

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

Dans iScroll.js Works

2
Sunil P

un autre exemple de code pour solution. et merci pour les commentaires précédents! Using Jquery!

Après:

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

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

en fonction chargée

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

Je suis en retard mais je vous laisse ma solution.

Si vous utilisez jQuery, vous pouvez essayer cela.

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

il n'importe qui.

je sais que toutes vos réponses sont correctes mais j'ai une nouvelle façon de vous offrir. sans script Java ni fonctions drop iscroll.

le gros problème de toute cette solution est que lorsque vous faites défiler l'élément de l'entrée, vous ne pouvez pas faire défiler la page. quand vous faites juste une ou deux entrées, ça n'a pas vraiment d'importance, mais quand la page est un formulaire, vous avez un gros problème pour faire défiler la page.

la solution que je propose consiste à envelopper l’entrée dans une étiquette ou à créer l’étiquette avec un pointeur sur l’entrée. faites ensuite avec positionnement absolu et z-index l’étiquette au-dessus de l’entrée. lorsque vous touchez l’étiquette, vous focalisez l’entrée.

et exemple s'il vous plaît

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

vous pouvez également de cette manière mettre le côté étiquette de l'entrée et avec la position absolue de l'entrée, placer cela dans la zone d'étiquette

travaille à 100%, vérifiez

1
g.e.manor
  // 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
  });

Pour moi, il me suffit d’ajouter un clic: true sur la dernière ligne ... J'ai passé toute la journée à déboguer et à mettre en œuvre toutes les solutions suggérées sans succès ...

1
Zennichimaro

Même si vous avez exclu des éléments de formulaire dans onBeforeScrollStart (), il existe un autre bogue dans le navigateur/affichage Web Android 2.2/2.3:

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

Vous ne pouvez pas saisir de caractères chinois dans les éléments d’entrée du div avec un style CSS "-webkit-transform". L'iscroll 4 a appliqué le "-webkit-transform" au scroller div.

La solution consiste à conserver les champs de formulaire dans un div absolu en dehors du scroller.

0
diyism

Le bogue du navigateur Android est le résultat d'une très ancienne version de WebKit dans Android, même dans Android 4.3. La cause première du bogue - le traitement incorrect de l'événement de clic envoyé par iScroll au navigateur (la suppression de preventDefault cesse simplement d'envoyer cet événement de clic) Le navigateur Android Chrome est exempt de ce bogue car il a mis à niveau la bibliothèque WebKit.

En attente de la mise à niveau Android WebKit de Google.

0
Anatoliy Shuba

essayez cette solution if (e.target.nodeName.toLowerCase () == "select" || e.target.tagName.toLowerCase () == 'input' || e.target.tagName.toLowerCase () == 'textarea') __. {
revenir; }

0
Sukesh Marla

Voici une solution très facile qui a fonctionné pour moi. J'ai remarqué dans les navigateurs Android que, lors du chargement initial de la page, je ne pouvais pas cliquer sur une zone de sélection, mais que je pouvais cliquer sur un champ de saisie de texte que j'utilisais pour la recherche. Ensuite, j'ai remarqué qu'après avoir cliqué sur le champ de saisie de texte, il me reconnaît en cliquant sur une zone de sélection. Donc tout ce que j'ai fait a été d'ajouter ceci à la fonction javascript que j'utilisais pour charger la page de recherche ...

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

Ainsi, lorsque la page de recherche est chargée, elle se concentre automatiquement sur le champ de saisie de texte mais ne fait pas apparaître le clavier, ce qui est exactement ce que je voulais. Désolé, mon exemple n'est pas accessible au public, mais j'espère que cela pourra toujours aider quelqu'un.

0
Pete

Vérifie ça. Cela a résolu mon problème

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

En option j'ai sélectionné

click:false, preventDefaultException:{tagName:/.*/}
0
A Paul

Je suis un peu en retard pour le jeu, mais si quelqu'un est toujours intéressé, j'ai pris l'approche de @ bastien et l'ai légèrement modifié pour qu'il fonctionne sur Android. J'utilise JQM avec mon implémentation.

En gros, ce que j'ai fait était: 

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

}

En gros, tout ce que vous avez à faire est de détruire votre instance iScroll lorsqu'un élément de formulaire est sélectionné par l'utilisateur, mais avant de commencer le défilement (onBeforeScrollStart) et si l'utilisateur clique sur un élément de l'élément avec l'attribut personnalisé data-iscroll="scroller", il en utilisant iScroll comme d'habitude.

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

Il existe un bogue avec Android lorsque -webkit-transform: translate3d est appliqué à un conteneur contenant une zone de sélection ou un champ de mot de passe [1]. La zone encadrée pour activer ces éléments bouge et ne correspond pas à ce que vous pensez. En outre, les zones de mot de passe Paint se trouvent à un emplacement différent, de sorte qu'il apparaît que vous avez deux éléments d'entrée au lieu d'un.

Je travaille chez AppMobi et nous avons développé une bibliothèque de boîtes à outils qui contient des correctifs pour ces problèmes. Nous avons mis en place des widgets de sélection personnalisés et un remplacement du champ de saisie du mot de passe. Vérifiez ci-dessous.

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

[1] Je pense que l'auteur du commentaire parle de ce bogue https://bugs.webkit.org/show_bug.cgi?id=50552

0
user258082

Ça marche pour moi !:

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