绑定已绑定到另一个元素的函数

时间:2013-01-15 02:50:11

标签: javascript jquery javascript-events jquery-selectors

我有一堆元素可以获得三个不同的类:neutralmarkedVmarkedX。当用户单击其中一个元素时,类会切换一次:中性 - > markedV - > markedX - >中性。每次单击都会切换类并执行一个函数。

$(document).ready(function(){
  $(".neutral").click(function markV(event) {
    alert("Good!");
    $(this).addClass("markedV").removeClass("neutral");
    $(this).unbind("click");
    $(this).click(markX(event));
  });
  $(".markedV").click(function markX(event) {
    alert("Bad!");
    $(this).addClass("markedX").removeClass("markedV");
    $(this).unbind("click");
    $(this).click(neutral(event));
  });
  $(".markedX").click(function neutral(event) {
    alert("Ok!");
    $(this).addClass("neutral").removeClass("markedX");
    $(this).unbind("click");
    $(this).click(markV(event));
  });
});

但显然这不起作用。我想我有三个障碍:

  1. 如何将更改元素正确绑定到已定义的函数,有时在实际定义之前?

  2. 如何确保将事件传递给新绑定的函数[我想这不是通过向函数发送'event'来实现的,就像在markX(事件)中一样)

  3. 整个事情看起来很重复,唯一改变的是警报行动(尽管每个功能的行为都不同,不一定是警报)。对此有更优雅的解决方案吗?

3 个答案:

答案 0 :(得分:1)

不需要经常绑定和取消绑定事件处理程序。

您应该为所有这些选项配备一个处理程序:

$(document).ready(function() {

    var classes = ['neutral', 'markedV', 'markedX'],
        methods = {
            neutral: function (e) { alert('Good!') },
            markedV: function (e) { alert('Bad!') },
            markedX: function (e) { alert('Ok!') },
        };

    $( '.' + classes.join(',.') ).click(function (e) {
        var $this = $(this);

        $.each(classes, function (i, v) {
            if ( $this.hasClass(v) ) {
                methods[v].call(this, e);
                $this.removeClass(v).addClass( classes[i + 1] || classes[0] );
                return false;
            }
        });
    });
});

这是小提琴:http://jsfiddle.net/m3CyX/

答案 1 :(得分:1)

对于此类情况,您需要将事件附加到更高的父级并委派事件。

请记住,事件附加到元素而不是类。

尝试这种方法

$(document).ready(function () {
  $(document).on('click', function (e) {
    var $target = e.target;
    if ($target.hasClass('markedV')) {
      alert("Good!");
      $target.addClass("markedV").removeClass("neutral");
    } else if ($target.hasClass('markedV')) {
      alert("Bad!");
      $target.addClass("markedX").removeClass("markedV");
    } else if ($target.hasClass('markedX')) {
      alert("Ok!");
      $target.addClass("neutral").removeClass("markedX");
    }
  });
});

为@Bergi建议

$(document).ready(function () {
  $(document).on('click', 'markedV',function (e) {
    alert("Good!");
    $(this).addClass("markedV").removeClass("neutral");
  });
  $(document).on('click', 'markedX',function (e) {
    alert("Bad!");
    $(this).addClass("markedX").removeClass("markedV");
  });
  $(document).on('click', 'neutral',function (e) {
    alert("Ok!");
    $(this).addClass("neutral").removeClass("markedX");
  });
});

此处文档可以替换为任何静态父容器..

答案 2 :(得分:0)

  

如何正确地将更改元素绑定到已定义的函数,有时在它实际定义之前?

您不将元素绑定到函数,将处理函数绑定到元素上的事件。您无法在定义函数之前使用该函数(但您可能会使用代码中声明的位置上方的函数 - 称为“吊装”)。

  

如何确保将事件传递给新绑定的函数[我猜这不是通过向函数发送'event'来实现的,就像在markX(event)中一样)

这就是调用处理程序时隐式发生的事情。您只需要传递函数 - do not call it!但问题是您无法从外部访问命名函数表达式。

  

整个事情看起来很重复,唯一改变的是警报行动(尽管每个功能都会采取不同的行动,不一定是警报)。对此有更优雅的解决方案吗?

是。仅使用一个处理程序,并动态决定在当前状态下执行的操作。不要稳定地绑定和取消绑定处理程序。或者使用event delegation