click event still triggered underneath div

廉价感情. 提交于 2019-12-23 18:04:29

问题


This is a PhoneGap app I'm building that I am testing on my laptop and then on an iphone using PhoneGap cli. I have an openlayers 3 map that records click events on it. I also have a div that masks the whole map when a menu shows. The idea being that when this masking div is clicked/tapped it hides itself but the map below DOES NOT register the click event. What is happening is that the map IS registering the click event so the masking div is hidden but the map then does something else because its been clicked, except it shouldn't have!

I've simplified my code down to the nitty gritty. Here is two screenshote of without and with the menu and masking div showing. The button bottom right is the one that opens the menu (.layers_menu_button).

This listens for clicks/taps on the masking div (#net_curtain2), and then hides it (note the commented out propagation thing is my attempt to stop the click/tap event here, but it doesn't make any difference). interaction_type is defined as click or touchend depending on what I'm testing on.

$(window).on("load", function() {
    $(document).on(interaction_type, "#net_curtain2", function(event) {
        // event.stopImmediatePropagation();
        hide_layers_menu();
    });

    setup_map();
});

...

function hide_layers_menu() {
    $('.layers_menu_button').fadeIn("fast", function() {
        // Animation complete
    });

    // remove hide class, add show class
    $('.layers_menu_button').removeClass('hide_layers_menu');
    $('.layers_menu_button').addClass('show_layers_menu');

    $('.layers_menu_content').hide();

    $("#net_curtain2").fadeOut("fast", function() {
        // Animation complete
    });

    var layers_menu_width = parseInt($(window).width()-60);
    $("#layers_menu").animate({
        bottom: "30px",
        right:"30px",
        width: "20px",
        height: "20px"
        }, 'fast', function() {
            // Animation complete
        });
}

function setup_map() {
    // create view
    view = new ol.View({
            center: ol.proj.transform([0.153733491897583, 52.655333117999774], 'EPSG:4326', 'EPSG:3857'),
            zoom: 17
        });

    // create layers of map types
    road = new ol.layer.Tile({
                source: new ol.source.BingMaps({
                    imagerySet: 'Road',
                    key: 'my_key_here',
                    disableZooming: true,
                    maxZoom: 19
                })
            });

    map = new ol.Map({
        target: $('#map')[0],
        layers: [
            road
        ],
        view: view,
        controls : ol.control.defaults({
            attribution:false,
            zoom:false,
            rotate: false
        })
    });

    // check if net_curtain is visible and only act if NOT
    map.on('click', function(evt) {
        if($('#net_curtain2').is(':hidden'))
        {
            console.log("net curtain hidden");
        }
        else
        {
            console.log("net curtain showing");
        }
    });

    var interactions = map.getInteractions().getArray();
    var pinchRotateInteraction = interactions.filter(function(interaction) {
        return interaction instanceof ol.interaction.PinchRotate;
    })[0];
    pinchRotateInteraction.setActive(false);
}

So what happens is that if you click on the map when the menu is not showing, the console logs out 'net curtain hidden', which is correct. But if you open the menu and then click on the masking div (net curtain) it closes the menu and hide the net curtain, which is correct, but then it THEN triggers 'net curtain hidden' which is wrong! I need it to just stop at hiding the net curtain.

What the most frustrating is that it works on my laptop but not on the phone. And changing map.on('click'... to map.on(interaction_type... mean it doesn't trigger any click/tap events on the map. I'm baffled.


回答1:


Your mobile browser is attempting to emulate click events I believe.

Calling event.preventDefault(); should solve your problem.

Try the code:

$(document).on(interaction_type, "#net_curtain2", function(event) {
    event.preventDefault();
    hide_layers_menu();
});

Explanation:

I believe your issue is the way mobile browsers emulate click events. One thing to always remember when developing for mobile browsers is that they attempt to emulate click events if nothing has explicitly prevented the default action. The order of events goes like this:

  1. touchstart
  2. touchmove
  3. touchend
  4. mouseover
  5. mousemove
  6. mousedown
  7. mouseup
  8. click

So, by not calling event.preventDefault() in any touch event your mobile browser assumes you want it to continue through that event chain, until it fires a click event (it's this click event that's giving you issues).

This can be confusing since calling event.stopPropagation() stops the event from bubbling up the event chain - which is what one would naturally assume is happening. But you should always remember to use preventDefault() inside touch event handlers, so the default mouse-emulation handling doesn’t occur.

For a more in-depth explanation, read this.

Possibly related: link



来源:https://stackoverflow.com/questions/39508472/click-event-still-triggered-underneath-div

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!