Click events from two scripts on same element?

◇◆丶佛笑我妖孽 提交于 2020-01-06 05:43:07

问题


Edit: I think I got the solution! I want to try and fix this myself before I ask for further help = )

First script inhibits the second one from functioning as the click event from the first one overides the second one. Because the second one does not function it is impossible to open the drop down menu to select a list item to trigger the first scripts click.

What I tried was replacing all return false statements with event.stopPropagation(). Didnt work however. Tried re-ordering my scripts but that failed as well. I was thinking of making my second script target another parent div but that didnt work either.I also tried event.stopImmediatePropagation() and .bind methods.

Any idea?

First script that makes the drop down function. Contains click event.

    function DropDown(el) {
        this.f = el;
        this.placeholder = this.f.children('span');
        this.opts = this.f.find('ul.dropdown > li');
        this.val = '';
        this.index = -1;
        this.initEvents();
    }
    DropDown.prototype = {
        initEvents : function() {
            var obj = this;

            obj.f.on('click', function(event){
                $(this).toggleClass('active');
                return false;
            });

            obj.opts.on('click',function(){
                var opt = $(this);
                obj.val = opt.text();
                obj.index = opt.index();
                obj.placeholder.text(obj.val);
            });
        },
        getValue : function() {
            return this.val;
        },
        getIndex : function() {
            return this.index;
        }
    }

    $(function() {

        var f = new DropDown( $('#f') );

        $(document).click(function() {
            // all dropdowns
            $('.filter-buttons').removeClass('active');
        });

    });

Second script that does the filtering, also contains click event:

jQuery(document).ready(function(e) {
    var t = $(".filter-container");
    t.imagesLoaded(function() {
        t.isotope({
            itemSelector: "figure",
            filter: "*",
            resizable: false,
            animationEngine: "jquery"
        })
    });
    $(".filter-buttons a").click(function(evt) {
  var n = $(this).parents(".filter-buttons");
        n.find(".selected").removeClass("selected");
        $(this).addClass("selected");
        var r = $(this).attr("data-filter");
        t.isotope({
            filter: r
        });
    evt.preventDefault();
});
    $(window).resize(function() {
        var n = $(window).width();
        t.isotope("reLayout")
    }).trigger("resize")
});

html structure

<div id="f" class="filter-buttons" tabindex="1">
                    <span>Choose Genre</span>
                    <ul class="dropdown">
                        <li><a href="#" data-filter="*" class="selected">All</a></li>
                        <li><a href="#" data-filter=".electronic">Electronic</a></li>
                        <li><a href="#" data-filter=".popular">Popular</a></a></li>
                    </ul>
                </div>

回答1:


I think you're going to need to simplify this to figure out what's going on. There's actually not enough information to see what elements the events are being attached to here.

For argument's sake, open the console and try the following:

$(document).on('click', function() { console.log('first'); return false; });
$(document).on('click', function() { console.log('second'); return false; });

Then click in the page. You'll see that both events are triggered. It might well be that your code is actually attaching the events to different elements (you don't say anywhere). If that's the case then you need to understand how event bubbling works in the DOM.

When you trigger an event, say a click on an element, that event will fire on that element, and then on it's parent, then grandparent etc all the way to the root node at the top.

You can change this behaviour by calling functions in the event itself. evt.stopPropagation tells the event to not bubble up to the ancestor nodes. evt.preventDefault tells the browser not to carry out the default behaviour for a node (eg, moving to the page specified in the href for an A tag).

In jQuery, return false from an event handler is a shortcut for, evt.preventDefault and evt.stopPropagation. So that will stop the event dead in its tracks.

I imagine you have something like:

<div event_two_on_here>
    <a event_one_on_here>
</div>

If the thing that handles event_one_on_here calls stopPropagation then event_two_on_here will never even know it has happened. Calling stopPropagation explicitly, or implicitly (return false) will kill the event before it travels to the parent node/event handler.

UPDATE: In your case the issue is that the handler on .filter-buttons a is stopping the propagation (so #f doesn't get to run its handler).

$(".filter-buttons a").click(function(evt) {
    // your code here...

    // Don't do this - it stops the event from bubbling up to the #f div
    // return false;

    // instead, you'll probably just want to prevent the browser default
    // behaviour so it doesn't jump to the top of the page ('url/#')
    evt.preventDefault();
});



回答2:


This doesn't really solve your problem but I was bored while drinking my coffee and felt like helping you write your dropdown plugin a little nicer

My comments below are inline with code. For uninterrupted code, see DropDown complete paste.


We start with your standard jQuery wrapper (function($){ ... })(jQuery)

(function($) {

  // dropdown constructor
  function DropDown($elem) {

First we'll make some private vars to store information. By using this.foo = ... we expose things (probably) unnecessarily. If you need access to these vars, you can always create functions to read them. This is much better encapsulation imo.

    // private vars
    var $placeholder = $elem.children("span");
    var $opts    = $elem.find("ul.dropdown > li")
    var value    = "";
    var index    = -1;

Now we'll define our event listeners and functions those event listeners might depend on. What's nice here is that these functions don't have to access everything via this.* or as you were writing obj.f.* etc.

    // private functions
    function onParentClick(event) {
      $elem.toggleClass("active");
      event.preventDefault();
    }

    function onChildClick(event) {
      setValue($(this));
      event.preventDefault();
    }

    function setValue($opt) {
      value = $opt.text();
      index = $opt.index();
      $placeholder.text(value);
    }

Here's some property descriptors to read the index and value

    // properties for reading .index and .value
    Object.defineProperty(this, "value", {
      get: function() { return value; }
    });

    Object.defineProperty(this, "index", {
      get: function() { return index; }
    });

Lastly, let's track each instance of DropDown in an array so that the user doesn't have to define a special listener to deactivate each

    // track each instance of
    DropDown._instances.push(this);
  }

This is the array we'll use to track instances

  // store all instances in array
  DropDown._instances = [];

This event listener deactivate each "registered" instance of DropDown

  // deactivate all
  DropDown.deactiveAll = function deactiveAll(event) {
    $.each(DropDown._instances, function(idx, $elem) {
      $elem.removeClass("active");
    });
  }

Here's the document listener defined right in the plugin! The user no longer has to set this up

  // listener to deactiveAll dropdowns
  $(document).click(DropDown.deactiveAll);

Might as well make it a jQuery plugin since everything in our DropDown constructor relies upon jQuery. This let's the user do var x = $("foo").dropdown();

  // jQuery plugin
  $.fn.dropdown = function dropdown() {
    return new DropDown($(this));
  };

Close the wrapper

})(jQuery);

Now here's how you use it

$(function() {
  var x = $('#f').dropdown();

  // get the value
  f.value;

  // get the index
  f.index;
});

Anyway, yeah I know this doesn't really help you with your click listeners, but I hope this is still useful information to you. Off to the Post Office now!



来源:https://stackoverflow.com/questions/26316109/click-events-from-two-scripts-on-same-element

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