要素を切り替えるネイティブjQuery関数はありますか?


174

2つの要素をjQueryで簡単に交換できますか?

可能であれば、1行でこれを実行することを検討しています。

select要素があり、オプションを上下に移動するための2つのボタンがあり、すでにselectセレクターとdestinationセレクターが配置されていますが、ifを使用していますが、もっと簡単な方法があるかどうか疑問に思っていました。


マークアップとコードサンプルを投稿できますか?
コンスタンティンタルクス

これはjQueryではなくJavaScriptの問題です。単一の命令でDOM要素を交換することはできません。ただし、[Paolo's answer](#698386)は素晴らしいプラグインです;)
Seb

1
グーグルからここに来る人々のために:非常にシンプルで私にとって完璧に働いたロティフの答えをチェックしてください
モーリス

1
@モーリス、私は承認された回答を変更しました
juan

1
これは、要素が互いに並んでいる場合にのみ要素を交換します!受け入れられた回答を変更してください。
Serhiy、2015

回答:


233

jQueryのみを使用してこれを解決する興味深い方法を見つけました。

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

または

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

:)


2
ええ、これはうまくいくはずです:ドキュメントはこう言っています:「この方法で選択された要素が他の場所に挿入された場合、それはターゲットの前に移動されます(クローンではありません)」。
Ridcully、2012年

12
私はこのオプションが一番好きです!シンプルでうまく互換性があります。ただし、読みやすくするためにel1.insertBefore(el2)とel1.insertAfter(el2)を使用したいのですが。
モーリス

6
ただし、ここでDOMを操作しているので、1つの注意事項(このページのすべてのソリューションに当てはまると思います)。移動する要素内にiframeが存在する場合、削除と追加はうまく機能しません。iframeがリロードされます。また、現在のURLではなく、元のURLにリロードされます。非常に迷惑ですが、セキュリティ関連です。私はこれに対する解決策を見つけていません
モーリス

202
2つの要素が互いに直接隣接していない限り、これは2つの要素を交換しません。
BonyT

12
これはもはや受け入れられた答えではありません。一般化されたケースでは機能しません。
thekingoftruth 2014

79

パウロの言うとおりですが、なぜ彼が関係する要素を複製しているのかはわかりません。これは実際には必要ありません。要素とその子孫に関連付けられている参照やイベントリスナーは失われます。

プレーンな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);
}

2
docs.jquery.com/Clone-「true」を渡すと、イベントも複製されます。私は最初にそれを複製せずに試しましたが、それはあなたの現在のことをしています:最初のものを2番目のものと交換し、最初のものをそのまま残しています。
Paolo Bergantino

<div id = "div1"> 1 </ div> <div id = "div2"> 2 </ div>があり、swapNodes(document.getElementById( 'div1')、document.getElementById( 'div2')を呼び出した場合); <div id = "div1"> 1 </ div> <div id = "div2"> 1 </ div>を取得
Paolo Bergantino

3
ああ、aの次の兄弟がb自体であるというまれなケースがあります。上記のスニペットで修正されました。jQueryはまったく同じことを行っていました。
ボビンス2009年

イベントとIDを保持する必要がある非常に順序に敏感なリストがあり、これは魅力のように機能します!ありがとう!
Teekin、2011年

1
この質問のタイトルを技術的に満たすには、jQueryバージョンを追加する必要があるように感じます。:)
thekingoftruth 2014

70

いいえ、ありませんが、1つ上げることができます。

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つの要素とのみ一致する場合にのみ機能することに注意してください。


2
それらを複製する必要がありますか?
フアン

おそらく、html()を使用して直接書き込むことができますか?
エドジェームス

2
@Ed Woodcock行うと、これらの要素のバインドされたイベントが失われます。
アレックス

2
divが隣り合っていない場合に最適です:)
Elmer

これは受け入れられる答えになるはずです。jQueryを拡張して、要求されたものを提供します。
アリスワンダー

40

この問題には、受け入れられた回答やボビンスの回答では処理されないエッジケースがたくさんあります。クローン作成を含む他のソリューションは正しい方向に進んでいますが、クローン作成は高価で不要です。2つの変数を交換する方法の古くからの問題があるため、クローンを作成したくなります。その1つは、変数の1つを一時変数に割り当てることです。この場合、割り当て(クローン)は必要ありません。ここにjQueryベースのソリューションがあります:

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

7
これは受け入れられる答えになるはずです。複製はイベントトリガーを削除するため、必要ありません。私は自分のコードでこの正確なメソッドを利用しています。
thekingoftruth 2014

1
これはより良い答えです!私はたまたま、jqueryのソート可能な要素である、スワップされた要素の子としてulを持っています。Paolo Bergantinoの回答と交換した後、リストアイテムはもうドロップできませんでした。user2820356の回答では、すべてがまだ正常に機能しています。
agoldev 2015年

20

これらの答えの多くは一般的なケースでは単に間違っていますが、実際に機能する場合でも不必要に複雑なものがあります。jQuery .before.afterメソッドは、やりたいことのほとんどを行いますが、多くのスワップアルゴリズムが機能するためには、3番目の要素が必要です。これは非常に単純です。移動する間、一時的な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.after($that).remove();

  return $this;
}

1)一時的なdivをtemp前に置くthis

2)this前に移動that

3)that後に移動temp

3b)削除 temp

その後、単に

$(selectorA).swapWith(selectorB);

デモ:http : //codepen.io/anon/pen/akYajE


2
これが最良の答えです。他のすべての要素は要素が互いに隣接していると想定しています。これはあらゆる状況で機能します。
brohr

11

2つのクローンは必要ありませんが、1つは必要です。パオロベルガンティーノの答えを見てみましょう。

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

より速くする必要があります。2つの要素のうち小さい方を渡すと、処理速度も向上します。


4
これとPaoloの問題は、IDは一意である必要があるため、クローン作成が機能しないため、IDを持つ要素を交換できないことです。この場合、Bobinceのソリューションは機能します。
Ruud

別の問題は、これがcopy_toからイベントを削除することです。
Jan Willem B

8

以前はこんなテクニックを使っていました。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');

これは最善の解決策end()ですが、チェーンを継続しない場合は必要ありません。いかがですか$('element1').clone().before('element2').end().replaceWith('element2');
robisrob 2015年

1
ただ気づいclone()任意のjqueryのを保存していないdata()ユーザーが指定しない限り、clone(true) あなたがいない失うすべてのデータを行うので、あなたは、ソートしている場合、重要な区別を-
robisrob

3

選択した複数のオプションを上下に移動できる機能を作りました

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

これは、コードの記述方法とコードの実行方法の両方において非効率的です。
ブレーズ

これは私たちのアプリの主要な機能ではなかったので、少量のオプションで使用しています。早くて簡単なものが欲しかった...これを改善できたら嬉しいです!いいね!
Tom Maeckelberghe

3

クローンなしの他のもの:

スワップする実際の要素と名目上の要素があります。

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

その後insert <div> beforeremoveその後のみが必要です、あなたが確認できない場合は、常に前の要素があることを確認してください(私の場合はそうです)


それとも、ただのためにチェックすることができ.prev()の長さ、および0場合、.prepend().parent():)そうすれば、あなたは余分な要素を作成する必要はありません。
jave.web 2016年

2

jQueryプラグイン「スワップ可能」を見てください

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

「ソート可能」に基づいて構築されており、ソート可能(ドラッグアンドドロップ、プレースホルダーなど)のように見えますが、スワップとドラッグの2つの要素のみを交換します。他のすべての要素は影響を受けず、現在の位置にとどまります。


2

これは@lotifの回答ロジックに基づく回答ですが、少し一般化されています

要素が実際に移動さ れる前/後に追加/前に追加する場合
=>クローンは不要
=>イベントが保持されます

起こり得る2つのケースがあります

  1. 1つのターゲットに「.prev()ious」がある=> もう1つのターゲットを置くことができ.after()ます。
  2. 1つのターゲットはその最初の子です.parent()=> もう1つ.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>

2

これは、親要素内で複数の子要素を上下に移動するための私の解決策です。リストボックス(<select multiple></select>)で選択したオプションを移動するのに適しています

上に移動:

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


1

魔女が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オブジェクトでは使用しないでください


1

各要素のコピーが複数ある場合は、自然にループで何かを行う必要があります。最近このような状況になりました。私が切り替えるのに必要な2つの繰り返し要素には、クラスとコンテナー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"));
});

1

私はこのスニペットでそれをやった

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

1

私は.after().before()を使用してデータベースのobjの順序を変更するためのテーブルを作成したので、これは私が実験したものです。

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

obj2の前にobj1を挿入し、

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

逆も同様です。

したがって、obj1がobj3の後に、obj2がobj4の後にあり、場所obj1とobj2を変更したい場合は、次のようにします。

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

これはそれを行うはずですが、何らかの種類のインデックスがまだない場合は、.prev()と.next()を使用してobj3とobj4を見つけることができます。


これは受け入れられた回答者の単なる詐欺ではなく、構文エラーが含まれています。これをコピーパスタしましたか?
clockw0rk 2018

えno?これは私の前の会社での私の仕事のための作業コードです。横に私が使用する方法とどのような状況で指摘することを確認しました。なぜ誰かを騙す必要があるのですか?また、オブジェクトのインデックスを取得する方法も示します。これが、受け入れられた回答が完了していないとコメントされた理由です。
Tran Vu Dang Khoa 2018

では、なぜafter($())ではなくafter $()なのですか
clockw0rk

ああ、私はそれを見なかった、ありがとう。私はそれをメモリから入力しましたが、会社を辞めた後もそのコードを保持する権利はありません
Tran Vu Dang Khoa

0

nodeAとnodeBが兄弟<tr>で、同じの2つが好きな<tbody>場合、それらを使用する$(trA).insertAfter($(trB))$(trA).insertBefore($(trB))交換するだけで使用できます。$(trA).remove()以前に呼び出す必要はありません。それ以外の場合は、クリックイベントを再バインドする必要があります。$(trA)


0
$('.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();
    });
};

おかげヤニック・ギネスhttps://jsfiddle.net/ARTsinn/TVjnr/


-2

最良のオプションは、clone()メソッドでそれらを複製することです。


1
これにより、コールバックとバインディングがすべて削除されます
thekingoftruth 14

-2

とても簡単にできると思います。たとえば、次の構造があるとします:...

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

そして結果は

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

jquery:

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

お役に立てば幸いです。


2
この解決策はすでに指摘されており、2つの要素が互いに隣接していなければ機能しません。
BernaMariano
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.