【问题标题】:Refactoring jQuery to use $(this) and add/remove classes from another element重构 jQuery 以使用 $(this) 并从另一个元素添加/删除类
【发布时间】:2013-09-20 13:08:12
【问题描述】:

所以我有这个想法,我正在 Codepen 上工作。我已经让它按原样工作,但在我去添加更多可点击区域之前,我已经意识到非常需要重构和干燥东西。到目前为止它可以工作,但它非常丑陋,并且会涉及大量重复的代码。

所以我试图用一个 switch 语句替换许多 $(.class).click(function() { ... }); 函数,该语句使用 $(this) 来填充单个 .click 函数。但我迷路了。

您可以在此处查看所有内容并进行编辑:http://codepen.io/lukewatts/pen/ubtmI

我觉得我很接近但我碰壁了。顶部注释掉的部分是 DRY 尝试,而目前未注释的是工作版本。单击 min、off、max 字词或 LED 以查看其工作情况。

非常感谢您就此提供任何建议。说实话,PHP 是我的主要语言。

附:我有 leds.click(function() { ... }) 并用 leds.on(function() { ... }) 替换它,但仍然没有。

【问题讨论】:

  • 以前没见过case switch 的方法...有趣。
  • 我认为Code Review 可能是提出问题的更好地方。不过,我正在看一看,我认为您的 switch 想法不一定更好。
  • 你应该从 JSLint 或 JSHint 开始。
  • 我认为奇怪的case switch 实际上是问题所在......它是这样工作的吗? :-/
  • 看那是我接管的 php 逻辑。 Switch 语句在 PHP 中很常见,但我在 Javascript 中看不到它们。我承认在这种情况下使用 $(...) 感觉各种错误。但是我已经检查了 MDN 的语法,开关应该没问题。

标签: javascript jquery click switch-statement this


【解决方案1】:

我了解您要做什么,但这不是 jQuery 对象的工作方式。为了检查对象是否匹配选择器,您必须使用.is()

因此,您将无法使用switch,但您必须使用一系列链接的ifs 来实现您尝试的目标,例如

if ( $this.is('.led[data-level="one"]') )
   var led = $('p.min a');
   var level = "one";

我已将您的 CodePen 示例更新为以这种方式工作:Codepen

不过,正如我在对该问题的评论中提到的那样,我不会在这里进行任何代码审查,只是修复对您不起作用的问题。老实说,我不确定这实际上是否比您的 messy 原始方法更好。

【讨论】:

  • 谢谢。这确实有效。实际上,表盘周围将有 13 个 LED / 电平,所以我想我用 13 个 ifs 换取 13 .click(function() { ... }) 无论如何都不理想。但是一个开关或者是否设置变量比仅仅做 .click 方法 13 次更可重用......我希望。再次感谢。
  • 重构代码总是一个有趣的挑战。当然要寻找更清洁的东西,但最终要瞄准更易于维护的东西。大多数时候这两个重叠,但其他时候我们根本没有问正确的问题。表盘做得很好,看起来很棒。
【解决方案2】:

重构后的版本对我来说看起来不错。如果你不喜欢使用 addClass 和 removeClass 你可以直接改变元素的 class 属性:

indicator.attr("class", "one on");

【讨论】:

  • 谢谢。我只是认为不止一两个 remove/addClass 看起来很乱。一旦我不止一次重复某件事,我总是会尝试寻找一个更简单的替代方案。我会试试这个。
  • Indicator.attr("class", "indicator off"); 完美运行。谢谢。干净多了。
【解决方案3】:

您的 switch 语句不起作用的原因是因为每次创建 jQuery 对象时,它都会获得一个 Id,因此当 switch 尝试将 $this$(p.min a) 之类的选择器进行比较时,它们不会是平等的。但是,如果您对 $.is 使用多个 if 语句,您可以比较:

$this = $(this)
if($this.is('p.min a')) {
   // do work
} else if($this.is('p.max a')) {
   // do work
}

但是,我不推荐这种方法。对于更复杂的页面,我推荐使用 Knockout.js 之类的绑定框架。对于一些小事,你会增加很多复杂性。为清楚起见:如果这成为更大控制集或系统的一部分,则绑定框架将很有用。对于按原样进行的控制,绑定框架和 OP 当前的方法都是矫枉过正的。

【讨论】:

  • 啊,好吧。这仍然是错误的。 switch($this) case .is('p.min a'): 等等。是不是因为我不能在一个案例中使用 jQuery 方法?只是当需要大量 ifelse 时,我总是使用 switch(诚然在 PHP 中)。
  • 既然您为这么简单的事情提出了一个绑定框架,我想收回我的赞成票。
  • @Mathletics 我不是说“用于更复杂的页面”吗?我没有为这个简单的控件推荐绑定框架。
  • @LukeWatts 对,你不能在这样的开关中使用 jQuery 方法。
  • 另外,还有十二个 LED 灯会环绕表盘...因此现在需要重新考虑所有问题。所以就目前而言,我正在用 13 个 .click(...) 实例换取 13 个 if 语句。一个框架可能是必要的,但这只是 codepen 的一个想法。 ://
【解决方案4】:

您可能想查看事件委托,我发现它对保持 DRY 非常有帮助。点击将 DOM 树冒泡到更高的元素,您可以在祖先元素上注册您的处理程序。这实际上是理想的,因为您只需将单个处理程序绑定到单个元素,而不是绑定到多个元素,因此除了更简洁的代码之外,您还可以实现性能优势。

首先,将所有.led 元素包装在<div id="leds"> 中:

 <div id="leds">
     <a href="#" class="led" data-level="one"></a>
     <a href="#" class="led" data-level="thirteen"></a>
 </div>

现在创建你的处理程序:

   $('#leds').bind('click', function(e){
    var target = e.target;
    var $target = $(target);

       //do interesting stuff
       if (target.nodeName === 'A') {
            var level = $target.data('level');
            if(level = 'one'){
                //do more interesting stuff
            }
        }       
     }
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多