【问题标题】:Toggling click handlers in Javascript在 Javascript 中切换点击处理程序
【发布时间】:2013-01-03 08:21:33
【问题描述】:

我有一个使用 jQuery 的bind() 附加事件的 HTML 按钮,如下所示:

$('#mybutton').bind('click', myFirstHandlerFunction);

myFirstHandlerFunction 中,我希望这个处理程序用新的处理程序mySecondHandlerFunction 替换自己,如下所示:

function myFirstHandlerFunction(e) {
    $(this).unbind('click', myFirstHandlerFunction).bind('click', mySecondHandlerFunction);
}

在第二个单击处理程序mySecondHandlerFunction 中,我想将按钮切换回其原始状态:取消绑定mySecondHandlerFunction 处理程序并重新附加原始处理程序myFirstHandlerFunction,如下所示:

function mySecondHandlerFunction(e) {
    $(this).unbind('click', mySecondHandlerFunction).bind('click', myFirstHandlerFunction);
}

这很好用,除了一个小细节:因为点击事件还没有通过按钮的每个点击处理程序传播,所以点击事件被传递到按钮的下一个点击处理程序,它恰好是之前的处理程序只是绑定在前一个处理程序中。最终结果是mySecondHandlerFunctionmyFirstHandlerFunction 执行后立即执行。

这个问题可以通过在每个处理程序中调用e.stopPropagation() 来轻松解决,但这具有取消可能已独立附加的任何其他点击处理程序的负面影响。

有没有一种方法可以安全、一致地在两个点击处理程序之间切换,而不必停止点击事件的传播?

【问题讨论】:

  • 为什么不使用标志来检查要调用的处理程序并始终附加主处理程序。

标签: javascript jquery events click handler


【解决方案1】:

更新: 由于toggle() 的这种形式在 jQuery 1.9 中被删除,下面的解决方案不再起作用。见this question 替代品。

看起来toggle() 可以解决您的问题:

$("#mybutton").toggle(myFirstHandlerFunction, mySecondHandlerFunction);

上面的代码将注册myFirstHandlerFunctionmySecondHandlerFunction 以在交替点击时被调用。

【讨论】:

  • .toggle(eventHandlers) 在 jQuery 1.8 中被贬值,并在 1.9+ 中被移除。这不再是一个可行的选择。 -Source
【解决方案2】:

只需使用布尔值来切换处理程序的功能,无需调整正在侦听的处理程序:

$('#mybutton').bind('click', myHandlerFunction);
var first = true;

function myHandlerFunction(e) {
    if(first){
        // Code from the first handler here;
    }else{
        // Code from the second handler here;
    }
    first = !first; // Invert `first`
}

【讨论】:

  • 由于您使用的是 jQuery,.toggle 可能会更好,但 +1 用于展示如何在不使用 .toggle 的情况下执行此操作的逻辑
  • 如上所述,toggle 在 1.9 中已弃用并在 1.10 中删除。不要使用它。
  • 我更喜欢使用数据属性而不是全局属性:stackoverflow.com/a/2459225/781695
【解决方案3】:

这个解决方案是一个 hack,但它对于你的粗活来说又短又甜:

$('#myButton').click(function() {
  (this.firstClk = !this.firstClk) ? firstHandler(): secondHandler();
});

这是一个 hack,因为它将一个新属性直接放在this 上,这是点击目标 HTML DOM 元素,这可能不是最佳实践。但是,它因此避免了创建任何新的全局变量,并且可以同时在不同按钮上不加改变地使用。

请注意,三元运算的第一部分使用= 而不是=====,即它是一个赋值,而不是一个比较。另请注意,第一次单击按钮时,this.firstClk 未定义但立即被否定,使得三元运算的第一部分第一次计算为 true

这是一个工作版本:

$('#a > button').click(function() {(this.firstClk = !this.firstClk) ? a1(): a2();});
$('#b > button').click(function() {(this.firstClk = !this.firstClk) ? b1(): b2();});

function a1() {$('#a > p').text('one');}
function a2() {$('#a > p').text('two');}

function b1() {$('#b > p').text('ONE');}
function b2() {$('#b > p').text('TWO');}
div {display: inline-block;width: 10em;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a"><p>not yet clicked</p><button>click</button></div>
<div id="b"><p>NOT YET CLICKED</p><button>CLICK</button></div>

【讨论】:

    【解决方案4】:

    我今天正在看这个,并意识到如果没有列出全局变量,仍然没有办法做到这一点。我想出了以下方法来向 ESRI 底图添加位置,但它通常也可以工作:

    function addLocationClickHandler() {
        var addLocationClick = overviewMap.on('click', function (event) {
            addLocationClick.remove();
        })
        $('#locationAddButton').one('click', function (cancelEvent) {
            addLocationClick.remove();
            $('#locationAddButton').on('click', addLocationClickHandler)
        });
    }
    
    $('#locationAddButton').on('click', addLocationClickHandler)
    

    这应该允许您在覆盖点击处理程序的部分中放置其他内容,而不需要全局变量。

    【讨论】:

      【解决方案5】:

      这将有助于在您的按钮上添加data-click-state 属性

      $(document).ready(function() {
          $('#mybutton').on('click', function() {
              if ($(this).attr('data-click-state') == 1) {
                  $(this).attr('data-click-state', 0)
                  myFirstHandlerFunction();
              } else {
                  $(this).attr('data-click-state', 1)
                  mySecondHandlerFunction();
              }
          });
      });
      

      【讨论】:

      • 我喜欢这种方法!
      【解决方案6】:

      像这样:

      $(this).bind('click', myMasterHandler);
      
      handler = 0;
      
      function myMasterHandler(e) {
          if(handler == 0) {
              myFirstHandler(e);
              handler = 1;
          } else {
              mySecondHandler(e);
              handler = 0;
          }
      }
      

      【讨论】:

      • 反对票不是我的,但它可能与 handler 是全局而不是本地有关,或者与使用 01 而不是布尔值有关,或者与事实有关this 的当前值未正确传播到处理程序。
      猜你喜欢
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 2012-02-11
      • 2014-03-12
      • 1970-01-01
      • 2010-12-08
      • 2011-02-24
      • 1970-01-01
      相关资源
      最近更新 更多