【问题标题】:Is there a native jQuery function to switch elements?是否有本机 jQuery 函数来切换元素?
【发布时间】:2010-10-16 10:42:23
【问题描述】:

我可以用 jQuery 轻松交换两个元素吗?

如果可能的话,我希望用一行来做到这一点。

我有一个选择元素,我有两个按钮可以向上或向下移动选项,并且我已经有了选定和目标选择器,我用 if 来做,但我想知道是否有更简单的方式。

【问题讨论】:

  • 你能发布你的标记和代码示例吗?
  • 这不是 jQuery 而是 JavaScript:你不能在一条指令中交换 DOM 元素。但是,[Paolo 的回答](#698386) 是一个很棒的插件 ;)
  • 对于从谷歌来到这里的人:查看 lotif 的答案,非常简单,对我来说非常有效。
  • @Maurice,我改变了接受的答案
  • 这只会交换相邻的元素!请更改接受的答案。

标签: jquery swap javascript


【解决方案1】:

我发现了一种仅使用 jQuery 即可解决此问题的有趣方法:

$("#element1").before($("#element2"));

$("#element1").after($("#element2"));

:)

【讨论】:

  • 我最喜欢这个选项!简单且很好地兼容。尽管我喜欢使用 el1.insertBefore(el2) 和 el1.insertAfter(el2) 来提高可读性。
  • 一个旁注虽然..(我猜这适用于此页面上的所有解决方案),因为我们在这里操作 DOM。当您正在移动的元素中存在 iframe 时,删除和添加效果不佳。 iframe 将重新加载。它还将重新加载到它的原始网址而不是当前网址。非常烦人但与安全相关。我还没有找到解决方案
  • 这不会交换两个元素,除非两个元素紧挨着。
  • 这只会交换相邻的元素,否则 Paolo 的答案是正确的。
  • 这不再是公认的答案。它不适用于一般情况。
【解决方案2】:

Paulo 是对的,但我不确定他为什么要克隆相关元素。这并不是真正必要的,并且会丢失与元素及其后代关联的任何引用或事件侦听器。

这是一个使用普通 DOM 方法的非克隆版本(因为 jQuery 并没有任何特殊功能可以使这个特定操作更容易):

function swapNodes(a, b) {
    var aparent = a.parentNode;
    var asibling = a.nextSibling === b ? a : a.nextSibling;
    b.parentNode.insertBefore(a, b);
    aparent.insertBefore(b, asibling);
}

【讨论】:

  • docs.jquery.com/Clone - 传递“true”也会克隆事件。我试过不先克隆它,但它正在做你目前的事情:它将第一个与第二个交换,并将第一个保持原样。
  • 如果我有
    1
    2
    并调用 swapNodes(document.getElementById('div1'), document.getElementById('div2'));我得到
    1
    1
  • 啊,有一个极端情况,a 的下一个兄弟是 b 本身。固定在上面的sn-p中。 jQuery 也在做同样的事情。
  • 我有一个对顺序非常敏感的列表,需要保留事件和 ID,这就像一个魅力!谢谢!
  • 我觉得您应该添加一个 jQuery 版本以在技术上满足这个问题的标题。 :)
【解决方案3】:

不,没有,但你可以拿出一个:

jQuery.fn.swapWith = function(to) {
    return this.each(function() {
        var copy_to = $(to).clone(true);
        var copy_from = $(this).clone(true);
        $(to).replaceWith(copy_from);
        $(this).replaceWith(copy_to);
    });
};

用法:

$(selector1).swapWith(selector2);

请注意,这仅在选择器每个仅匹配 1 个元素时才有效,否则可能会产生奇怪的结果。

【讨论】:

  • 是否需要克隆它们?
  • 也许你可以直接使用 html() 来编写它们?
  • @Ed Woodcock 如果你这样做了,我很确定你会失去那些元素上的绑定事件。
  • 当 div 不相邻时效果很好:)
  • 这应该是公认的答案。它扩展了 jQuery 以提供所要求的内容。
【解决方案4】:

这个问题有很多边缘情况,接受的答案或 bobince 的答案没有处理这些情况。其他涉及克隆的解决方案都在正确的轨道上,但克隆既昂贵又不必要。我们很想克隆,因为如何交换两个变量的古老问题,其中一个步骤是将变量之一分配给临时变量。在这种情况下,不需要分配(克隆)。这是一个基于 jQuery 的解决方案:

function swap(a, b) {
    a = $(a); b = $(b);
    var tmp = $('<span>').hide();
    a.before(tmp);
    b.before(a);
    tmp.replaceWith(b);
};

【讨论】:

  • 这应该是公认的答案。克隆会删除任何事件触发器并且没有必要。我在我的代码中使用了这种精确的方法。
  • 这是更好的答案!我碰巧有一个 ul 作为我交换元素的子元素,这是一个 jquery 可排序元素。与 Paolo Bergantino 的答案交换后,列表项无法再删除。有了 user2820356 的回答,一切仍然正常。
【解决方案5】:

jQuery .before 方法可用于通过添加临时 3rd 元素作为书签来交换元素 - 在移动内容时将临时 DOM 元素作为占位符。 .

$.fn.swapWith = function(that) {
  var $this = this;
  var $that = $(that);
  
  // create temporary placeholder
  var $temp = $("<div>");
  
  // 3-step swap
  $this.before($temp);
  $that.before($this);
  $temp.before($that).remove();
        
  return $this;
}
  1. 将临时 div temp 放在 this 之前

  2. this移到that之前

  3. that移到temp之前

3b) 删除temp

那就这样用吧

$(selectorA).swapWith(selectorB);

演示:https://jsfiddle.net/7t1hz94y/

【讨论】:

  • 这是最好的答案,所有其他人都假设元素彼此相邻。这适用于任何情况。
  • 谢谢,这个解决方案适用于所有情况,而且解释得详细简单,也可以标记为正确答案。我猜这个stackoverflow.com/a/61212946/903998 很相似,但解释得更少,也更复杂一些。
  • @robisrob 和其他读者可能会注意到 3) move that after temp 也可以是 3) move that before temp,因为 temp 在用作锚点后将被删除。
【解决方案6】:

您不需要两个克隆,一个就可以了。采取 Paolo Bergantino 的答案,我们有:

jQuery.fn.swapWith = function(to) {
    return this.each(function() {
        var copy_to = $(to).clone(true);
        $(to).replaceWith(this);
        $(this).replaceWith(copy_to);
    });
};

应该更快。传入两个元素中较小的一个也应该会加快速度。

【讨论】:

  • 这个问题和 Paolo 的问题是它们不能交换带有 ID 的元素,因为 ID 必须是唯一的,因此克隆不起作用。 Bobince 的解决方案在这种情况下确实有效。
  • 另一个问题是这会从 copy_to 中删除事件。
【解决方案7】:

我以前使用过这样的技术。我将它用于http://mybackupbox.com 上的连接器列表

// clone element1 and put the clone before element2
$('element1').clone().before('element2').end();

// replace the original element1 with element2
// leaving the element1 clone in it's place
$('element1').replaceWith('element2');

【讨论】:

  • 这是 imo 的最佳解决方案,但如果您不继续链,则无需 end()$('element1').clone().before('element2').end().replaceWith('element2'); 怎么样
  • 刚刚注意到 clone() 不会保留任何 jquery data() 除非您指定 clone(true) - 如果您正在排序,这是一个重要的区别,因此您不会丢失所有数据
【解决方案8】:

我制作了一个功能,可让您向上或向下移动多个选定的选项

$('#your_select_box').move_selected_options('down');
$('#your_select_boxt').move_selected_options('up');

依赖关系:

$.fn.reverse = [].reverse;
function swapWith() (Paolo Bergantino)

首先它检查第一个/最后一个选择的选项是否能够向上/向下移动。 然后循环遍历所有元素并调用

swapWith(element.next() 或 element.prev())

jQuery.fn.move_selected_options = function(up_or_down) {
  if(up_or_down == 'up'){
      var first_can_move_up = $("#" + this.attr('id') + ' option:selected:first').prev().size();
      if(first_can_move_up){
          $.each($("#" + this.attr('id') + ' option:selected'), function(index, option){
              $(option).swapWith($(option).prev());
          });
      }
  } else {
      var last_can_move_down = $("#" + this.attr('id') + ' option:selected:last').next().size();
      if(last_can_move_down){
        $.each($("#" + this.attr('id') + ' option:selected').reverse(), function(index, option){
            $(option).swapWith($(option).next());
        });
      }
  }
  return $(this);
}

【讨论】:

  • 这在代码编写方式和执行方式上都是低效的。
  • 这不是我们应用程序的主要功能,我只是将它与少量选项一起使用。我只是想要一些快速简单的东西......如果你能改进它,我会很高兴的!那太好了!
【解决方案9】:

另一个没有克隆的:

我有一个实际元素和一个名义元素要交换:

            $nominal.before('<div />')
            $nb=$nominal.prev()
            $nominal.insertAfter($actual)
            $actual.insertAfter($nb)
            $nb.remove()

那么 insert &lt;div&gt; before 和之后的 remove 只需要,如果你不能确保,总是有一个元素之前(在我的情况下)

【讨论】:

  • 或者你可以只检查.prev()的长度,如果为0,那么.prepend().parent() :) 这样你就不需要创建额外的元素了。
【解决方案10】:

这是我在父元素内上下移动多个子元素的解决方案。 适用于在列表框中移动选定的选项 (&lt;select multiple&gt;&lt;/select&gt;)

向上移动:

$(parent).find("childrenSelector").each((idx, child) => {
    $(child).insertBefore($(child).prev().not("childrenSelector"));
});

向下移动:

$($(parent).find("childrenSelector").get().reverse()).each((idx, child) => {
    $(opt).insertAfter($(child).next().not("childrenSelector"));
});

【讨论】:

    【解决方案11】:

    看看 jQuery 插件“Swapable”

    http://code.google.com/p/jquery-swapable/

    它建立在“可排序”之上,看起来像可排序(拖放、占位符等),但只交换两个元素:拖放。所有其他元素不受影响并保持在当前位置。

    【讨论】:

      【解决方案12】:

      这是一个基于@lotif的回答逻辑的回答,但更笼统

      如果您在元素实际移动之后/之前追加/前置
      => 无需克隆
      => 事件保留

      可能发生两种情况

      1. 一个目标有一些“.prev()ious”=>我们可以把另一个目标.after()那个。
      2. 一个目标是它的.parent()的第一个子目标=>我们可以.prepend()将另一个目标作为父目标。

      代码

      这段代码可以写得更短,但为了便于阅读,我保持这种方式。请注意,必须预先存储父母(如果需要)和以前的元素。

      $(function(){
        var $one = $("#one");
        var $two = $("#two");
        
        var $onePrev = $one.prev(); 
        if( $onePrev.length < 1 ) var $oneParent = $one.parent();
      
        var $twoPrev = $two.prev();
        if( $twoPrev.length < 1 ) var $twoParent = $two.parent();
        
        if( $onePrev.length > 0 ) $onePrev.after( $two );
          else $oneParent.prepend( $two );
          
        if( $twoPrev.length > 0 ) $twoPrev.after( $one );
          else $twoParent.prepend( $one );
      
      });
      

      ...随意将内部代码包装在一个函数中:)

      示例小提琴附加了额外的点击事件以演示事件保存...
      小提琴示例: https://jsfiddle.net/ewroodqa/

      ...适用于各种情况 - 甚至是以下情况:

      <div>
        <div id="one">ONE</div>
      </div>
      <div>Something in the middle</div>
      <div>
        <div></div>
        <div id="two">TWO</div>
      </div>
      

      【讨论】:

        【解决方案13】:

        如果你想交换 jQuery 对象中选择的两个项目,你可以使用这个方法

        http://www.vertstudios.com/blog/swap-jquery-plugin/

        【讨论】:

          【解决方案14】:

          我想要一个不使用 clone() 的解决方案,因为它对附加事件有副作用,这就是我最终要做的事情

          jQuery.fn.swapWith = function(target) {
              if (target.prev().is(this)) {
                  target.insertBefore(this);
                  return;
              }
              if (target.next().is(this)) {
                  target.insertAfter(this);
                  return
              }
          
              var this_to, this_to_obj,
                  target_to, target_to_obj;
          
              if (target.prev().length == 0) {
                  this_to = 'before';
                  this_to_obj = target.next();
              }
              else {
                  this_to = 'after';
                  this_to_obj = target.prev();
              }
              if (jQuery(this).prev().length == 0) {
                  target_to = 'before';
                  target_to_obj = jQuery(this).next();
              }
              else {
                  target_to = 'after';
                  target_to_obj = jQuery(this).prev();
              }
          
              if (target_to == 'after') {
                  target.insertAfter(target_to_obj);
              }
              else {
                  target.insertBefore(target_to_obj);
              }
              if (this_to == 'after') {
                  jQuery(this).insertAfter(this_to_obj);
              }
              else {
                  jQuery(this).insertBefore(this_to_obj);
              }
          
              return this;
          };
          

          它不能与包含多个 DOM 元素的 jQuery 对象一起使用

          【讨论】:

            【解决方案15】:

            如果每个元素都有多个副本,则自然需要循环执行某些操作。我最近有这种情况。我需要切换的两个重复元素有类和一个容器 div,如下所示:

            <div class="container">
              <span class="item1">xxx</span>
              <span class="item2">yyy</span>
            </div> 
            and repeat...
            

            以下代码允许我遍历所有内容并反转...

            $( ".container " ).each(function() {
              $(this).children(".item2").after($(this).children(".item1"));
            });
            

            【讨论】:

              【解决方案16】:

              这个sn-p我已经做到了

              // Create comments
              var t1 = $('<!-- -->');
              var t2 = $('<!-- -->');
              // Position comments next to elements
              $(ui.draggable).before(t1);
              $(this).before(t2);
              // Move elements
              t1.after($(this));
              t2.after($(ui.draggable));
              // Remove comments
              t1.remove();
              t2.remove();
              

              【讨论】:

                【解决方案17】:

                我做了一个表,用于更改数据库中 obj 的顺序使用 .after() .before(),所以这是我的实验。

                $(obj1).after($(obj2))
                

                在 obj2 之前插入 obj1 和

                $(obj1).before($(obj2)) 
                

                反之亦然。

                所以如果obj1在obj3之后,obj2在obj4之后,如果你想改变obj1和obj2的位置,你会这样做

                $(obj1).before($(obj4))
                $(obj2).before($(obj3))
                

                应该这样做 顺便说一句,如果您还没有某种索引,您可以使用 .prev() 和 .next() 来查找 obj3 和 obj4。

                【讨论】:

                • 这不仅仅是对已接受答案的抄袭,它包含错误的语法错误。这是你复制的吗?
                • 不是吗?这是我在以前公司工作的工作代码。此外,我确保指出如何使用以及在哪种情况下使用。为什么我需要敲诈一个人?我还给出了如何获取对象的索引,这就是为什么接受的答案被评论为未完成。
                • 那为什么是 after$() 而不是 after($())
                • 哦,是的,我没看到,谢谢。我凭记忆输入,离开公司后无权保留该代码
                【解决方案18】:
                $('.five').swap('.two');
                

                像这样创建一个 jQuery 函数

                $.fn.swap = function (elem) 
                {
                    elem = elem.jquery ? elem : $(elem);
                    return this.each(function () 
                    {
                        $('<span></span>').insertBefore(this).before(elem.before(this)).remove();
                    });
                };
                

                感谢 Yannick Guinness https://jsfiddle.net/ARTsinn/TVjnr/

                【讨论】:

                  【解决方案19】:

                  如果 nodeA 和 nodeB 是兄弟姐妹,喜欢在同一个 &lt;tbody&gt; 中的两个 &lt;tr&gt;,您可以使用 $(trA).insertAfter($(trB))$(trA).insertBefore($(trB)) 交换它们,它适用于我。并且之前不需要调用$(trA).remove(),否则需要在$(trA)上重新绑定一些点击事件

                  【讨论】:

                    【解决方案20】:

                    目前任何主流浏览器都不需要使用 jquery 来交换元素。原生 dom 方法,insertAdjacentElement 无论位于何处都可以解决问题:

                    var el1 = $("el1");
                    var el2 = $("el2");
                    el1[0].insertAdjacentElement("afterend", el2[0]);
                    

                    【讨论】:

                      【解决方案21】:

                      最好的选择是使用 clone() 方法克隆它们。

                      【讨论】:

                      • 这会删除所有回调和绑定
                      【解决方案22】:

                      我认为你可以很简单地做到这一点。例如,假设您有下一个结构: ...

                      <div id="first">...</div>
                      <div id="second">...</div>
                      

                      结果应该是

                      <div id="second">...</div>
                      <div id="first">...</div>
                      

                      jquery:

                      $('#second').after($('#first'));
                      

                      希望对你有帮助!

                      【讨论】:

                      • 这个解决方案已经被指出并且不起作用,除非两个元素紧挨着。
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-10-27
                      • 1970-01-01
                      • 2011-07-11
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多