Pergunta

My website is responsive and for narrow views the navigation switches to an icon that shows the nav on click. To close the navigation panel you can click the icon again or anywhere outside of the nav modal. This is the JS to manage clicks outside of the nav modal:

$(document).mousedown(function(e) {
    var clicked = $(e.target);
    if (clicked.is("#navigation") || clicked.parents().is("#navigation") || clicked.is("#hamburger-nav-link")) {
        return;
    } else {
        $("#hamburger-nav-link").removeClass("hamburger-nav-active");
        $("#navigation").removeClass("mobile-nav");
    }
});

On mobile devices (well, my iPhone) when you tap the icon it closes the nav modal, but when you tap outside the nav modal nothing happens.

I tried implementing code from this SO question to map touch events to click events: JavaScript mapping touch events to mouse events

However this didn't work for me.

I pasted the code below the $(document).mousedown() function and it's all within a generic jQuery function. I've pasted the code below so you can see the whole thing. This file is called at the end of every page before the closing tag.

Any help is greatly appreciated, thanks!

$(function() {

// Mobile nav
$("#hamburger-nav-link").click(function() {
    if ($("#navigation").hasClass("mobile-nav")) {
        $(this).removeClass("hamburger-nav-active");
        $("#navigation").removeClass("mobile-nav");
    }
    else {
        $(this).addClass("hamburger-nav-active");
        $("#navigation").addClass("mobile-nav");
    }

    return false;
});

// Close modal if click event is outside of it
$(document).mousedown(function(e) {
    var clicked = $(e.target);
    if (clicked.is("#navigation") || clicked.parents().is("#navigation") || clicked.is("#hamburger-nav-link")) {
        return;
    } else {
        $("#hamburger-nav-link").removeClass("hamburger-nav-active");
        $("#navigation").removeClass("mobile-nav");
    }
});

function touchHandler(event)
{
        var touches = event.changedTouches,
                first = touches[0],
                type = "";
                 switch(event.type)
        {
                case "touchstart": type = "mousedown"; break;
                case "touchmove":    type="mousemove"; break;                
                case "touchend":     type="mouseup"; break;
                default: return;
        }

                         //initMouseEvent(type, canBubble, cancelable, view, clickCount, 
        //                     screenX, screenY, clientX, clientY, ctrlKey, 
        //                     altKey, shiftKey, metaKey, button, relatedTarget);

        var simulatedEvent = document.createEvent("MouseEvent");
        simulatedEvent.initMouseEvent(type, true, true, window, 1, 
                                                            first.screenX, first.screenY, 
                                                            first.clientX, first.clientY, false, 
                                                            false, false, false, 0/*left*/, null);

                                                                                                                                                                 first.target.dispatchEvent(simulatedEvent);
        event.preventDefault();
}

function init() 
{
        document.addEventListener("touchstart", touchHandler, true);
        document.addEventListener("touchmove", touchHandler, true);
        document.addEventListener("touchend", touchHandler, true);
        document.addEventListener("touchcancel", touchHandler, true);        
}

});
Foi útil?

Solução

Got it to work by simply binding the click and touchend event to the document. And then referencing the original hide/show function when the icon is clicked. HOWEVER, this introduced another problem of where clicking on the icon sometimes will double fire and you get weird behavior. Like closing and then reopening. I'm going to address this separately though. So, here's the answer:

The two functions touchHandler(event) and init() and the $(document).mousedown(function(e) { ... }); function and $("#hamburger-nav-link").click(function() { ... }); function are replaced with the following:

var navModalView = function() {
    if ($("#navigation").hasClass("mobile-nav")) {
        $("#hamburger-nav-link").removeClass("hamburger-nav-active");
        $("#navigation").removeClass("mobile-nav");
    }
    else {
        $("#hamburger-nav-link").addClass("hamburger-nav-active");
        $("#navigation").addClass("mobile-nav");
    }

    return false;
}

$(document).bind("click touchend", function(e) {
    var targetEl = $(e.target);

    if (targetEl.is("#navigation") || targetEl.parents().is("#navigation")) {
        return;
    }
    else if (targetEl.is("#hamburger-nav-link")) {
        navModalView();
        event.preventDefault();
    }
    else {
        $("#hamburger-nav-link").removeClass("hamburger-nav-active");
        $("#navigation").removeClass("mobile-nav");
    }
});

Outras dicas

I'm using this for my web project. may be this will work for mobile. try once :)

//GET ALL CLICK EVENT
$('html').click(function() {
    popmenu();
});

//Popupmenu Hide Function        
function popmenu(){
    var popmenuVisible = $(".popmenuclass").is("visible").toString();
    if (popmenuVisible=="true") {
            $(".popmenuclass").hide();
        }
} 

//IF you click on popupmenu then disable popmenu closing 
$(".popmenuclass").click(function(event){ event.stopPropagation();});
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top