【问题标题】:Binding a function that is already bound to another element绑定已经绑定到另一个元素的函数
【发布时间】:2019-09-10 00:23:19
【问题描述】:

我有一堆元素得到三个不同的类:neutralmarkedVmarkedX。当用户单击这些元素之一时,类会切换一次:中性 -> 标记V -> 标记X -> 中性。每次点击都会切换类并执行一个函数。

$(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. 如何确保将事件传递给新绑定的函数[我猜这不是通过像在 markX(event) 中那样向函数发送“事件”来完成的]

  3. 整个事情看起来是重复的,唯一改变的是警报操作(虽然每个函数的行为不同,但不一定是警报)。有没有更优雅的解决方案?

【问题讨论】:

  • 这一行的目的是什么:$(this).click(markV(event));?似乎这里代码的意图是在第一次用户单击后连续运行状态。
  • 你真的想要一个无限循环吗?
  • @pktangyue:没有无限循环
  • @Bergi 是的,我明白他想要什么

标签: javascript jquery jquery-selectors jquery-events


【解决方案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/

【讨论】:

    【解决方案2】:

    对于这种情况,您需要将事件附加到更高的父级并委托事件。

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

    试试这个方法

    $(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");
      });
    });
    

    这里的文档可以替换成任何静态父容器..

    【讨论】:

    • 为什么不使用 jQuery 进行事件委托?
    【解决方案3】:

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

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

    如何确保将事件传递给新绑定的函数[我猜这不是通过像 markX(event) 那样向函数发送“事件”来完成的]

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

    整个事情看起来是重复的,唯一改变的是警报动作(虽然每个函数的行为不同,不一定是警报)。有没有更优雅的解决方案?

    是的。仅使用一个处理程序,并动态决定在当前状态下要做什么。不要稳定地绑定和解除绑定处理程序。或者使用event delegation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 2020-02-20
      相关资源
      最近更新 更多