<select> drop down flashing on focus in ipho

2019-04-01 13:40发布

问题:

See this demo page in iphone http://jsbin.com/unese4/8 at the bottom of the page there is one dropdown which opens but doesn't work properly.

This question is related to this question iScroll 4 not working with form <select> element iPhone Safari and Android browser

回答1:

Actually, your issue is related to this question:

webkit-transform issue on safari using select elements

When an input gains focus in iOS Safari, it checks if the input is in view. If it isn’t, Safari forcibly scrolls the document, and the element(s) which contain the input, to make it visible.

iScroll uses a CSS transform to move the scrollable area around, and it looks like Safari’s behavior is broken for selects — it doesn't notice the transform, thinks that the select is out of view, and scrolls its container (#scrollable) to make it visible (again, not accounting for the transform), which puts it way out of view.

This is fundamentally an iOS bug, and should be reported to Apple by as many web developers as are affected by the issue! A workaround can be implemented most effectively inside iScroll, so I encourage you to report the issue to its developers.

That said, I have come up with a workaround, which you'll find at the bottom of this answer. You can use it by calling it, once, with your instance of iScroll:

workAroundiScrollSelectPositioning(myScroll);

A live demo is at your jsbin paste here. It triggers when a select gains focus, and does three things:

  1. Remembers the scroll position, and tells iScroll to immediately scroll to the top left corner (removing any transform), and sets the top and left CSS properties of the scroll area to the current scroll position. Visually, everything looks the same, but the scroll area is now positioned in a way that Safari will see.

  2. Block iScroll from seeing any touches (this is ugly, but it stops iScroll from applying a transform on the scroll area while we have it repositioned).

  3. When the select loses focus, put everything back to the way it was (restore the original position and transform and stop blocking iScroll).

There are still cases where the element's position can get screwed up (e.g. when a textarea has focus but is only partially in view, and you type and cause Safari to try to bring the rest of it in view), but these are best fixed in iScroll.


function workAroundiScrollSelectPositioning(iscroll){
    iscroll.scroller.addEventListener('focusin', function(e){
        if (e.target.tagName === 'SELECT') {
            var touchEvent = 'ontouchstart' in window ? 'touchmove' : 'mousemove',
                touchListener = {
                    handleEvent: function(e){
                        e.stopPropagation();
                        e.stopImmediatePropagation();
                    }
                },
                blurListener = {
                    oldX: iscroll.x,
                    oldY: iscroll.y,
                    handleEvent: function(e){
                        iscroll.scroller.style.top = '';
                        iscroll.scroller.style.left = '';
                        iscroll.scrollTo(this.oldX, this.oldY, 0);
                        e.target.removeEventListener('blur', blurListener, false);
                        iscroll.scroller.removeEventListener(touchEvent, touchListener, true);
                    }
                };
            iscroll.scroller.style.top = iscroll.y + 'px';
            iscroll.scroller.style.left = iscroll.x + 'px';
            iscroll.scrollTo(0, 0, 0);
            e.target.addEventListener('blur', blurListener, false);
            iscroll.scroller.addEventListener(touchEvent, touchListener, true);
        }
    }, false);
}


回答2:

you can use a custom table view on that place, suppose you want to show drop down list when user click on textfield. so when the user clcik on the textfield the delegate method get called TextFieldBeginEditing and inside that create a small table view . that look like a drop down list ...



回答3:

This is modified function workAroundiScrollSelectPositioning that worked for me.

function workAroundiScrollSelectPositioning(iscroll){
var touchEvent = 'ontouchstart' in window ? 'touchstart' : 'mousemove',
    oldX, oldY;
iscroll.scroller.addEventListener('focusin', function(e){
    if (e.target.tagName === 'SELECT') {
        var blurListener = {
                oldX: oldX,
                oldY: oldY,
                handleEvent: function(e){
                    iscroll.scroller.style['margin-top'] = '';
                    iscroll.scroller.style.left = '';
                    iscroll.scrollTo(oldX, oldY, 0);
                    e.target.removeEventListener('blur', blurListener, false);
                }
            };
        iscroll.scroller.style['margin-top'] = oldY + 'px';
        iscroll.scroller.style.left = oldX + 'px';
        iscroll.scrollTo(0, 0, 0);
        e.target.addEventListener('blur', blurListener, false);
    }
}, false);
iscroll.scroller.addEventListener(touchEvent, {
    handleEvent: function(e){
        if (e.target.tagName === 'SELECT') {
            oldX = iscroll.x,
            oldY = iscroll.y;
            e.stopPropagation();
            e.stopImmediatePropagation();
        }
    }
}, true);}