开发者

jQuery, $(document) is catching things I do not want it to

I have a dropdown menu system setup such as this...

This is the scripting section of the HTML page.

    $('.ui-dropdown').each(function () {
        $(this).dropdown();
    });

Then in the actual HTML...

            <li class="ui-dropdown">
                <a href="#">Dropdown Menu</a>
                <div>
                    Test
                </div>
            </li>

It works very simply. the div is set to display: none;. Then there are methods in the jQuery plugin.

    // drop the menu down so that it can be seen.
    function drop(e) {
        // show the menu section.
        options.menu.show();
    }

    // lift the menu up, hiding it from view.
    function lift(e) {
        开发者_如何学编程if (!options.menu.is(':visible'))
            return;
        options.menu.hide();
    }

Now, this works okay, but I want the menu to vanish when someone clicks anywhere other than the components inside of the div or the menu's triggering button. To try and fix that approach, I added this code.

$(document).click(lift);

This works, a little too well. It is catching (obviously) everything, including clicks to the button, the menu, etc. So I tried to fix it with the following functions.

options is defined as follows.

    options.button = $(this);
    options.menu = $(this).find('> div');
    options.links = $(this).find('> a');

    options.button.click(function (e) {
        options.menu.is(':visible') ? lift() : drop();
        e.stopPropogation(); // prevent event bubbling
    });

    options.links.click(function (e) {
        e.stopPropagation(); //prevent event bubbling
    });

    options.menu.click(function (e) {
        e.stopPropagation(); // prevent event bubbling
    });

But still no avail. How can I get $(document).click(lift) to be ignored when the menu I am wishing to be interacted with is clicked upon?


Below is the entire jQuery Plugin, just for reference.

jQuery.fn.dropdown = function () {
    var defaults = {
        class: null,
        button: null,
        menu: null
    };
    return this.each(function () {

        // initialize options for each dropdown list, since there
        // very well may be more than just one.
        var options = $.extend(defaults, options);

        // specifically assign the option components.
        options.class = '.' + $(this).attr('class');
        options.list = $(this); // keep a constant reference to the root.
        options.button = $(this).find('> a');
        options.menu = $(this).find('> div');

        // bind the lift event to the document click.
        // This will allow the menu to collapse if the user
        // clicks outside of it; but we will stop event bubbling to
        // keep it from being affected by the internal document links.
        $(document).click(function (e) {
            var $target = $(e.target);

            // check to see if we have clicked on one of the dropdowns, and if so, dismiss
            // the execution. We only want to lift one if we're not trying to interact with
            // one.
            if ($target.is(options.class) || $target.closest(options.class).length)
                return false;

            lift(e);
        });

        // when the button is clicked, determine the state of the
        // dropdown, and decide whether or not it needs to be lifted
        // or lowered.
        options.button.click(function (e) {
            options.menu.is(':visible') ? lift() : drop();
            e.stopPropogation(); // prevent event bubbling
        });

        // drop the menu down so that it can be seen.
        function drop(e) {
            // show the menu section.
            options.menu.show();
            // style the button that drops the menu, just for aesthetic purposes.
            options.list.addClass("open");
        }

        // lift the menu up, hiding it from view.
        function lift(e) {
            if (!options.menu.is(':visible'))
                return;
            options.menu.hide();


            // style the button that drops the menu, just for aesthetic purposes.
            options.list.removeClass('open');
        }
    });
};


You need to check the target on the click first to make sure that they didn't click in the list.

jQuery.fn.dropdown = function () {
    var defaults = {
        button: null,
        menu: null,
        links: null,
        identClass: 'my-dropdown'
    };
    var options = $.extend(defaults, options);

    return this.each(function () {
        $(this).addClass( options.identClass );
        /* ... */
    });

    /* ... */

    // lift the menu up, hiding it from view.
    function lift() {
        if (!options.menu.is(':visible'))
            return;
        options.menu.hide();
    }
    $(document).click(function(){
        var $target = $(e.target);
        if ( $target.is('.' + options.identClass) || $target.closest('.' + options.identClass).length ) {
            return;
        }
        lift();
    });
};


EDIT: This works, but unfortunately not in this case. Very poor performance, check out Nick Craver's comments below.

You can use the following selector to select everything but your menu.

$(':not(selector)')

You could try the faster equivalent method .not(selector) on your document selector to select everything on the page except the menu. Haven't tested this yet though.


In the lift function why not check if the elements id/class is not your dropdown, and if so, hide it.

For example:

function lift()
{
    if(this.getAttribute('class') != 'ui-dropdown')
    {
        // Hide it
    }
}


What I did in this instance is close all the menus and then display the one that was actually clicked.

For example:

$('.ui-dropdown').click(function() {
   $(this).siblings('.ui-dropdown').hide();
   $(this).show();
   return false;
});

$(document).click(function() {
    $('ui-dropdown').hide();
);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜