Is there a native jQuery function to switch elemen

2019-01-01 12:57发布

问题:

Can I easily swap two elements with jQuery?

I\'m looking to do this with one line if possible.

I have a select element and I have two buttons to move up or down the options, and I already have the selected and the destination selectors in place, I do it with an if, but I was wondering if there is an easier way.

回答1:

I\'ve found an interesting way to solve this using only jQuery:

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

or

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

:)



回答2:

Paulo\'s right, but I\'m not sure why he\'s cloning the elements concerned. This isn\'t really necessary and will lose any references or event listeners associated with the elements and their descendants.

Here\'s a non-cloning version using plain DOM methods (since jQuery doesn\'t really have any special functions to make this particular operation easier):

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);
}


回答3:

No, there isn\'t, but you could whip one up:

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);
    });
};

Usage:

$(selector1).swapWith(selector2);

Note this only works if the selectors only match 1 element each, otherwise it could give weird results.



回答4:

There are a lot of edge cases to this problem, which are not handled by the accepted answer or bobince\'s answer. Other solutions that involve cloning are on the right track, but cloning is expensive and unnecessary. We\'re tempted to clone, because of the age-old problem of how to swap two variables, in which one of the steps is to assign one of the variables to a temporary variable. The assignment, (cloning), in this case is not needed. Here is a jQuery-based solution:

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


回答5:

Many of these answers are simply wrong for the general case, others are unnecessarily complicated if they in fact even work. The jQuery .before and .after methods do most of what you want to do, but you need a 3rd element the way many swap algorithms work. It\'s pretty simple - make a temporary DOM element as a placeholder while you move things around. There is no need to look at parents or siblings, and certainly no need to clone...

$.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.after($that).remove();

  return $this;
}

1) put the temporary div temp before this

2) move this before that

3) move that after temp

3b) remove temp

Then simply

$(selectorA).swapWith(selectorB);

DEMO: http://codepen.io/anon/pen/akYajE



回答6:

You shouldn\'t need two clones, one will do. Taking Paolo Bergantino answer we have:

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

Should be quicker. Passing in the smaller of the two elements should also speed things up.



回答7:

I used a technique like this before. I use it for the connector list on 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\');


回答8:

I\'ve made a function which allows you to move multiple selected options up or down

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

Dependencies:

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

First it checks whether the first/last selected option is able to move up/down. Then it loops through all the elements and calls

swapWith(element.next() or 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:

an other one without cloning:

I have an actual and a nominal element to swap:

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

then insert <div> before and the remove afterwards are only needed, if you cant ensure, that there is always an element befor (in my case it is)



回答10:

take a look at jQuery plugin \"Swapable\"

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

it\'s built on \"Sortable\" and looks like sortable (drag-n-drop, placeholder, etc.) but only swap two elements: dragged and dropped. All other elements are not affected and stay on their current position.



回答11:

This is an answer based on @lotif\'s answer logic, but bit more generalized

If you append/prepend after/before the elements are actually moved
=> no clonning needed
=> events kept

There are two cases that can happen

  1. One target has something \" .prev() ious\" => we can put the other target .after() that.
  2. One target is the first child of it\'s .parent() => we can .prepend() the other target to parent.

The CODE

This code could be done even shorter, but I kept it this way for readability. Note that prestoring parents (if needed) and previous elements is mandatory.

$(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 );

});

...feel free to wrap the inner code in a function :)

Example fiddle has extra click events attached to demonstrate event preservation...
Example fiddle: https://jsfiddle.net/ewroodqa/

...will work for various cases - even one such as:

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


回答12:

This is my solution to move multiple children elements up and down inside the parent element. Works well for moving selected options in listbox (<select multiple></select>)

Move up:

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

Move down:

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


回答13:

If you\'re wanting to swap two items selected in the jQuery object, you can use this method

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



回答14:

I wanted a solution witch does not use clone() as it has side effect with attached events, here is what I ended up to do

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;
};

it must not be used with jQuery objects containing more than one DOM element



回答15:

If you have multiple copies of each element you need to do something in a loop naturally. I had this situation recently. The two repeating elements I needed to switch had classes and a container div as so:

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

The following code allowed me to iterate through everything and reverse...

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


回答16:

I have done it with this snippet

// 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:

I did a table for changing order of obj in database used .after() .before(), so this is from what i have experiment.

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

Is insert obj1 before obj2 and

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

do the vice versa.

So if obj1 is after obj3 and obj2 after of obj4, and if you want to change place obj1 and obj2 you will do it like

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

This should do it BTW you can use .prev() and .next() to find obj3 and obj4 if you didn\'t have some kind of index for it already.



回答18:

if nodeA and nodeB are siblings, likes two <tr> in the same <tbody>, you can just use $(trA).insertAfter($(trB)) or $(trA).insertBefore($(trB)) to swap them, it works for me. and you don\'t need to call $(trA).remove() before, else you need to re-bind some click events on $(trA)



回答19:

The best option is to clone them with clone() method.



回答20:

I think you can do it very simple. For example let\'s say you have next structure: ...

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

and the result should be

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

jquery:

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

I hope it helps!