简体   繁体   English

使用jQuery抽象将单击事件添加到按类选择的元素中

[英]Abstracting the adding of click events to elements selected by class using jQuery

I'm slowly getting up to speed with jQuery and am starting to want to abstract my code. 我正在慢慢了解jQuery,并开始想抽象我的代码。 I'm running into problems trying to define click events at page load. 我在尝试定义页面加载时的点击事件时遇到了问题。

In the code below, I'm trying to run through each div with the 'block' class and add events to some of its child elements by selecting them by class: 在下面的代码中,我试图通过“ block”类遍历每个div,并通过按类选择事件,将事件添加到其某些子元素中:

<script language="javascript" type="text/javascript">
$(document).ready(function (){

$('HTML').addClass('JS'); // if JS enabled, hide answers

 $(".block").each(function() { 
  problem = $(this).children('.problem');
  button = $(this).children('.showButton');

  problem.data('currentState', 'off');

  button.click(function() {
   if ((problem.data('currentState')) == 'off'){
    button.children('.btn').html('Hide');
    problem.data('currentState', 'on');
    problem.fadeIn('slow');
   } else if ((problem.data('currentState')) == 'on'){
    button.children('.btn').html('Solve');
    problem.data('currentState', 'off');
    problem.fadeOut('fast');
   }
   return false;

  });
 });
});
</script>

<style media="all" type="text/css">
.JS div.problem{display:none;}
</style>


<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 1</p>
    </div>
</div>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 2</p>
    </div>
</div>

Unfortunately using this, only the last of the divs' button actually works. 不幸的是,使用此功能时,只有div的最后一个按钮才有效。 The event is not 'localised' (if that's the right word for it?) ie the event is only applied to the last $(".block") in the each method. 该事件不是“本地化的”(如果它是正确的词?),即该事件仅应用于每种方法中的最后一个$(“。block”)。

So I have to laboriously add ids for each element and define my click events one by one. 因此,我必须努力为每个元素添加ID,然后逐个定义我的点击事件。 Surely there's a better way! 当然,有更好的方法! Can anyone tell me what I'm doing wrong? 谁能告诉我我在做什么错? And how I can get rid of the need for those IDs (I want this to work on dynamically generated pages where I might not know how many 'blocks' there are...) 以及如何摆脱对这些ID的需求(我希望它可以在动态生成的页面上工作,在这些页面上我可能不知道有多少个“块” ...)

<script language="javascript" type="text/javascript">
$(document).ready(function (){

$('HTML').addClass('JS'); // if JS enabled, hide answers

 // Preferred version DOESN'T' WORK  
 // So have to add ids to each element and laboriously set-up each one in turn...

 $('#problem1').data('currentState', 'off');

 $('#showButton1').click(function() {
  if (($('#problem1').data('currentState')) == 'off'){
   $('#showButton1 > a').html('Hide');
   $('#problem1').data('currentState', 'on');
     $('#problem1').fadeIn('slow');
  } else if (($('#problem1').data('currentState')) == 'on'){
   $('#showButton1 > a').html('Solve');
   $('#problem1').data('currentState', 'off');
     $('#problem1').fadeOut('fast');
  }
  return false;

 });


 $('#problem2').data('currentState', 'off');

 $('#showButton2').click(function() {
  if (($('#problem2').data('currentState')) == 'off'){
   $('#showButton2 > a').html('Hide');
   $('#problem2').data('currentState', 'on');
     $('#problem2').fadeIn('slow');
  } else if (($('#problem2').data('currentState')) == 'on'){
   $('#showButton2 > a').html('Solve');
   $('#problem2').data('currentState', 'off');
     $('#problem2').fadeOut('fast');
  }
  return false;

 });

});
</script>

<style media="all" type="text/css">
.JS div.problem{display:none;}
</style>



<div class="block">
    <div class="showButton" id="showButton1">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem" id="problem1">
      <p>Answer 1</p>
    </div>
</div>

<div class="block">
    <div class="showButton" id="showButton2">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem" id="problem2">
      <p>Answer 2</p>
    </div>
</div>

edited because I found the HTML :) 编辑,因为我发现了HTML :)

First: you need to declare "button" and "problem" with the var keyword. 首先:您需要使用var关键字声明“ button”和“ problem”。

Next, the click handler will be called in the context of the target element, so you shouldn't reference "button" inside it but "$(this)" instead. 接下来,将在目标元素的上下文中调用单击处理程序,因此您不应在其内部引用“按钮”,而应引用“ $(this)”。

Next, you're going to need to come up with a way to relate each button to its corresponding "problem" element. 接下来,您将需要提出一种将每个按钮与其对应的“问题”元素相关联的方法。 The handler can find the companion "problem" using jQuery DOM traversal routines: 处理程序可以使用jQuery DOM遍历例程找到伴随的“问题”:

button.click(function() {
  var $button = $(this), $problem = $button.closest('div.block').find('.problem');
  if (($problem.data('currentState')) == 'off'){
    $button.children('.btn').html('Hide');
    $problem.data('currentState', 'on');
    $problem.fadeIn('slow');
  } else if (($problem.data('currentState')) == 'on'){
    $button.children('.btn').html('Solve');
    $problem.data('currentState', 'off');
    $problem.fadeOut('fast');
  }
  return false;
});

Now another alternative would be to use the live mechanism, which would let you create only one handler function. 现在,另一种替代方法是使用live机制,该机制仅允许您创建一个处理函数。 It'd be pretty similar to this, but instead of binding the handler to each "button" <div> you'd just set it up and reference the selector: 这将非常相似,但是您无需将处理程序绑定到每个“按钮” <div> ,而是对其进行设置并引用选择器:

$('.button').live('click', function() {
  // as above
});

Sorry, not enough reputation to vote for any of the above as useful, which they most definitely were! 抱歉,没有足够的声誉来投票赞成以上任何一项,而它们绝对是对的!

The answer was actually quite simple - as @patrick and @Pointy rightly pointed out, all I needed to do was to add the var keyword to declare my two variables. 答案实际上很简单-正如@patrick和@Pointy正确指出的,我需要做的就是添加var关键字来声明我的两个变量。 doh! h!

I couldn't actually get the code suggestions to work but mine works fine now that it's been fixed with your help. 我实际上无法获得代码建议,但是由于您的帮助已将其修复,因此我的工作正常。 Thanks! 谢谢!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
    $(document).ready(function (){

    $('HTML').addClass('JS'); // if JS enabled, hide answers

     $(".block").each(function() { 
      var problem = $(this).children('.problem');
      var button = $(this).children('.showButton');

      problem.data('currentState', 'off');

      button.click(function() {
       if ((problem.data('currentState')) == 'off'){
        button.children('.btn').html('Hide');
        problem.data('currentState', 'on');
        problem.fadeIn('slow');
       } else if ((problem.data('currentState')) == 'on'){
        button.children('.btn').html('Solve');
        problem.data('currentState', 'off');
        problem.fadeOut('fast');
       }
       return false;

      });
     });
    });
    </script>

<style media="all" type="text/css">
.JS div.problem{display:none;}
</style>

</head>

<body>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 1</p>
    </div>
</div>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 2</p>
    </div>
</div>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 3</p>
    </div>
</div>

</body>
</html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM