草庐IT

javascript - 如何在 "up"和 "down"方向操作DOM时避免重复代码?

coder 2024-07-24 原文

我正在编写一个 JS webapp 客户端。用户可以编辑文本项列表/树(例如,待办事项列表或注释)。我经常使用 jQuery 操作 DOM。

用户可以使用键盘(类似于 GMail 中的 J/K 键)在列表中上下导航,并执行其他一些操作。其中许多操作都具有镜像“向上”/“向下”功能,例如

$.fn.moveItemUp = function() {
    var prev = this.getPreviousItem();
    prev && this.insertBefore(prev);
    // there's a bit more code in here, but the idea is pretty simple,
    // i.e. move the item up if there's a previous item in the list
}

$.fn.moveItemDown = function() {
    var next = this.getNextItem();
    next && this.insertAfter(next);
    // ....
}

现在,这种具有两个几乎相同函数的模式在我的代码中的多个位置重复出现,因为在项的列表/树上有许多操作几乎是对称的。

问题:如何优雅地重构它以避免代码重复?

到目前为止,我想出的简单方法是使用 .apply()...

$.fn.moveItem = function(direction) {
        var up = direction === 'up',
            sibling = up ? this.getPreviousItem() : this.getNextItem(), 
            func = up ? $.fn.insertBefore : $.fn.insertAfter;

        // ...

        if (! sibling) { return false; }

        func.apply(this, [ sibling ]);

        // ...
    };

当代码的其他元素的结构需要更改 moveUp/moveDown 时,好处是更容易维护。我已经多次需要稍微更改代码,而且我始终需要记住我需要在两个地方进行...

但我对“统一”版本不满意,因为:

  • 实现比简单的上移/下移更复杂,因此将来维护起来可能就不那么容易了。我喜欢简单的代码。所有这些参数、三元运算、.apply() 技巧在每个应该“向上”和“向下”的函数中......
  • 不确定显式引用 jQuery.fn.* 函数是否安全(毕竟它们应该通过将它们应用于 jQuery 对象 $('...').* 来使用)

在使用 DOM 或类似结构时,您如何解决那些“几乎相同的代码”情况?

最佳答案

您可以做的一件事是使用闭包来隐藏从用户传递的配置参数:

var mk_mover = function(direction){
     return function(){
         //stuff
     };
};

var move_up = mk_mover("up");
var move_down = mk_mover("down");

如果你想继续朝这个方向发展,基本上就变成了决定将参数传递给通用实现的最佳方式的问题,而且没有单一的最佳解决方案。


一个可能的方向是使用 OO 风格的方法,将配置“策略”对象传递给实现函数。

var mk_mover = function(args){
    var get_item = args.getItem,
        ins_next = args.insNext;
    return function(){
        var next = get_item.call(this);
        next && ins_next.call(this, next);
    };
 };

 var move_up = mk_mover({
     get_item : function(){ return this.getPrevious(); },
     get_next : function(x){ return this.insertBefore(x); }
 });

 var move_down = mk_mover({/**/});

我更喜欢在策略接口(interface)(方向之间不同的方法)较小且相对恒定时,以及当你想在未来打开添加新方向的可能性时这样做。

当我知道方向集和方法种类都不需要太多改变时,我也倾向于使用它,因为 JS 对 OO 的支持比对 switch 语句的支持更好。


另一个可能的方向是您使用的枚举方法:

var mk_mover = function(direction){
    return function(){
        var next = (
            direction === 'up' ? this.getNextItem() :
            direction === 'down' ? this.getPreviousItem() :
            null );

        if(next){
            if(direction === 'up'){
                this.insertAfter(next);
            }else if(direction === 'down'){
                this.insertBefore(next);
            }
        }

        //...
    };
}

有时您可以使用整洁的对象或数组而不是 switch 语句来使事情更漂亮:

var something = ({
    up : 17,
    down: 42
}[direction]);

虽然我不得不承认这有点笨拙,但它的优点是如果您的方向集很早就固定下来,您现在可以很灵活地在需要时添加新的 if-else 或 switch 语句,以自包含的方式(无需在其他地方向策略对象添加一些方法...)


顺便说一句,我认为您建议的方法处于我建议的两个版本之间令人不安的中间地带。

如果您所做的只是根据传递的值方向标记在函数内部进行切换,最好直接在需要的地方进行切换,而不必将事情重构为单独的函数,然后再做很多事情烦人的 .call 和 .apply 东西。

另一方面,如果您经历了定义和分离函数的麻烦,您可以直接从调用者那里接收它们(以策略对象的形式),而不是手动进行调度自己。

关于javascript - 如何在 "up"和 "down"方向操作DOM时避免重复代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10588470/

有关javascript - 如何在 "up"和 "down"方向操作DOM时避免重复代码?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  7. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  8. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  9. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  10. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

随机推荐