Apakah ada fungsi jQuery asli untuk mengganti elemen?


174

Bisakah saya dengan mudah bertukar dua elemen dengan jQuery?

Saya ingin melakukan ini dengan satu baris jika memungkinkan.

Saya memiliki elemen pilih dan saya memiliki dua tombol untuk bergerak ke atas atau ke bawah opsi, dan saya sudah memiliki pemilih yang dipilih dan tujuan di tempat, saya melakukannya dengan jika, tetapi saya bertanya-tanya apakah ada cara yang lebih mudah.


Bisakah Anda memposting markup dan sampel kode Anda?
Konstantin Tarkus

Ini bukan masalah jQuery tetapi JavaScript: Anda tidak dapat menukar elemen DOM dalam satu instruksi. Namun, [jawaban Paolo] (# 698386) adalah plugin yang bagus;)
Seb

1
Untuk orang-orang yang datang ke sini dari google: lihat jawaban lotif, sangat sederhana dan bekerja sempurna untuk saya.
Maurice

1
@Maurice, saya mengubah jawaban yang diterima
juan

1
Ini hanya menukar elemen jika mereka berada di samping satu sama lain! Tolong, ubah jawaban yang diterima.
Serhiy

Jawaban:


233

Saya telah menemukan cara yang menarik untuk menyelesaikan ini hanya menggunakan jQuery:

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

atau

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

:)


2
Ya, ini harus bekerja: Dokumentasi mengatakan: "Jika elemen yang dipilih dengan cara ini dimasukkan di tempat lain, itu akan dipindahkan sebelum target (tidak dikloning)".
Ridcully

12
Saya suka opsi ini yang terbaik! Sederhana dan kompatibel dengan baik. Allthough saya suka menggunakan el1.insertBefore (el2) dan el1.insertAfter (el2) untuk keterbacaan.
Maurice

6
Satu sidenote .. (yang saya kira berlaku untuk semua solusi pada halaman ini) karena kita memanipulasi DOM di sini. Menghapus dan menambahkan tidak berfungsi dengan baik ketika ada iframe hadir di dalam elemen yang Anda pindahkan. Iframe akan dimuat ulang. Juga akan memuat kembali ke url aslinya bukan yang saat ini. Sangat menjengkelkan tetapi terkait keamanan. Saya belum menemukan solusi untuk ini
Maurice

202
ini tidak menukar dua elemen kecuali kedua elemen tersebut bersebelahan.
BonyT

12
Ini seharusnya bukan jawaban yang diterima lagi. Ini tidak berfungsi dalam kasus umum.
thekingoftruth

79

Paulo benar, tapi saya tidak yakin mengapa dia mengkloning elemen yang terkait. Ini tidak benar-benar diperlukan dan akan kehilangan referensi atau acara pendengar yang terkait dengan elemen dan keturunan mereka.

Berikut adalah versi non-kloning yang menggunakan metode DOM biasa (karena jQuery tidak benar-benar memiliki fungsi khusus untuk membuat operasi khusus ini lebih mudah):

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 - meneruskannya "true" juga mengkloning acara. Saya mencoba tanpa mengkloningnya terlebih dahulu tetapi melakukan apa yang Anda miliki saat ini: itu menukar yang pertama dengan yang kedua dan meninggalkan yang pertama apa adanya.
Paolo Bergantino

jika saya memiliki <div id = "div1"> 1 </div> <div id = "div2"> 2 </div> dan memanggil swapNodes (document.getElementById ('div1'), document.getElementById ('div2') ); saya mendapatkan <div id = "div1"> 1 </div> <div id = "div2"> 1 </div>
Paolo Bergantino

3
Ah, ada kasus sudut di mana saudara berikutnya a adalah b sendiri. Diperbaiki dalam cuplikan di atas. jQuery melakukan hal yang persis sama.
bobince

Saya memiliki daftar yang sangat peka terhadap pesanan yang perlu menyimpan acara dan ID dan ini berfungsi seperti pesona! Terima kasih!
Teekin

1
Saya merasa seolah-olah Anda harus menambahkan versi jQuery untuk memenuhi judul pertanyaan ini secara teknis. :)
thekingoftruth

70

Tidak, tidak ada, tetapi Anda bisa menyiapkannya:

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

Pemakaian:

$(selector1).swapWith(selector2);

Catatan ini hanya berfungsi jika penyeleksi hanya mencocokkan 1 elemen masing-masing, jika tidak maka akan memberikan hasil yang aneh.


2
apakah perlu mengkloningnya?
juan

Mungkin Anda bisa menulisnya langsung menggunakan html ()?
Ed James

2
@ Ed Woodcock Jika Anda melakukannya, Anda akan kehilangan acara terikat pada elemen-elemen yang saya yakin.
alex

2
Bekerja dengan baik ketika divs tidak bersebelahan :)
Elmer

Ini harus menjadi jawaban yang diterima. Ini memperluas jQuery untuk memberikan apa yang diminta.
Alice Wonder

40

Ada banyak kasus tepi untuk masalah ini, yang tidak ditangani oleh jawaban yang diterima atau jawaban bobince. Solusi lain yang melibatkan kloning berada di jalur yang benar, tetapi kloning itu mahal dan tidak perlu. Kita tergoda untuk mengkloning, karena masalah kuno tentang bagaimana menukar dua variabel, di mana salah satu langkahnya adalah menetapkan salah satu variabel ke variabel sementara. Tugas, (kloning), dalam hal ini tidak diperlukan. Berikut ini adalah solusi berbasis jQuery:

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

7
Ini harus menjadi jawaban yang diterima. Kloning menghilangkan pemicu peristiwa apa pun dan tidak perlu. Saya menggunakan metode yang tepat ini dalam kode saya.
thekingoftruth

1
Ini jawaban yang lebih baik! Saya senang memiliki ul sebagai anak dari elemen bertukar saya, yang merupakan elemen jquery sortable. Setelah bertukar dengan jawaban Paolo Bergantino, daftar item tidak bisa dijatuhkan lagi. Dengan jawaban user2820356 semuanya masih berfungsi dengan baik.
agoldev

20

Banyak dari jawaban ini benar-benar salah untuk kasus umum, yang lain tidak perlu rumit jika mereka bahkan bekerja. JQuery .beforedan .aftermetode melakukan sebagian besar dari apa yang ingin Anda lakukan, tetapi Anda memerlukan elemen ke-3 cara banyak algoritma swap bekerja. Ini cukup sederhana - jadikan elemen DOM sementara sebagai pengganti saat Anda memindahkan barang. Tidak perlu melihat orang tua atau saudara kandung, dan tentu saja tidak perlu mengkloning ...

$.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) meletakkan div sementara tempsebelumthis

2) bergerak this sebelumnyathat

3) bergerak that setelahtemp

3b) hapus temp

Maka sederhananya

$(selectorA).swapWith(selectorB);

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


2
Ini adalah jawaban terbaik, semua yang lain menganggap elemen-elemennya bersebelahan. Ini berfungsi dalam setiap situasi.
brohr

11

Anda seharusnya tidak perlu dua klon, satu akan dilakukan. Mengambil jawaban Paolo Bergantino, kita memiliki:

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

Seharusnya lebih cepat. Melewati elemen yang lebih kecil dari dua elemen juga harus mempercepat.


4
Masalah dengan ini, dan Paolo, adalah bahwa mereka tidak dapat bertukar elemen dengan ID karena ID harus unik sehingga kloning tidak berfungsi. Solusi Bobince memang berhasil dalam kasus ini.
Ruud

Masalah lain adalah ini akan menghapus acara dari copy_to.
Jan Willem B

8

Saya menggunakan teknik seperti ini sebelumnya. Saya menggunakannya untuk daftar konektor di 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');

ini adalah solusi imo terbaik, tetapi tidak perlu end()jika Anda tidak melanjutkan rantai. bagaimana dengan$('element1').clone().before('element2').end().replaceWith('element2');
robisrob

1
perhatikan clone()saja tidak menyimpan jquery apa pun data()kecuali Anda menentukan clone(true) - perbedaan penting jika Anda menyortir sehingga Anda tidak kehilangan semua data Anda
robisrob

3

Saya telah membuat fungsi yang memungkinkan Anda untuk memindahkan beberapa opsi yang dipilih ke atas atau ke bawah

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

Ketergantungan:

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

Pertama memeriksa apakah opsi pertama / terakhir yang dipilih dapat bergerak naik / turun. Kemudian ia melewati semua elemen dan panggilan

swapWith (element.next () atau 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);
}

Ini tidak efisien, baik dalam cara kode ditulis dan bagaimana kinerjanya.
Blaise

Itu bukan fitur utama aplikasi kami dan saya hanya menggunakannya dengan sejumlah kecil opsi. Saya hanya menginginkan sesuatu yang cepat & mudah ... Saya akan senang jika Anda dapat meningkatkan ini! Itu akan luar biasa!
Tom Maeckelberghe

3

yang lain tanpa kloning:

Saya memiliki elemen aktual dan nominal untuk ditukar:

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

kemudian insert <div> beforedan removesesudahnya hanya diperlukan, jika Anda tidak dapat memastikan, bahwa selalu ada elemen sebelum (dalam kasus saya itu)


Atau Anda bisa memeriksa .prev()panjangnya, dan jika 0, maka .prepend()ke .parent():) Dengan begitu Anda tidak perlu membuat elemen tambahan.
jave.web

2

lihat di plugin jQuery "Swapable"

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

itu dibangun di atas "Sortable" dan terlihat seperti sortable (drag-n-drop, placeholder, dll.) tetapi hanya menukar dua elemen: diseret dan dilepaskan. Semua elemen lain tidak terpengaruh dan tetap pada posisi mereka saat ini.


2

Ini adalah jawaban berdasarkan @lotif logika jawaban , tetapi sedikit lebih umum

Jika Anda menambahkan / menambahkan setelah / sebelum elemen benar-benar dipindahkan
=> tidak ada clonning yang diperlukan
=> acara disimpan

Ada dua kasus yang bisa terjadi

  1. Satu target memiliki sesuatu " .prev()ious" => kita dapat menempatkan target lain .after()itu.
  2. Satu target adalah anak pertama dari itu .parent()=> kita dapat .prepend()target lain untuk orang tua.

Kode

Kode ini dapat dilakukan lebih pendek, tetapi saya tetap menggunakan cara ini agar mudah dibaca. Perhatikan bahwa orangtua yang berprestasi (jika perlu) dan elemen sebelumnya adalah wajib.

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

});

... jangan ragu untuk membungkus kode bagian dalam suatu fungsi :)

Contoh biola memiliki acara klik ekstra terlampir untuk menunjukkan pelestarian acara ...
Contoh biola: https://jsfiddle.net/ewroodqa/

... akan bekerja untuk berbagai kasus - bahkan satu seperti:

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

2

Ini adalah solusi saya untuk memindahkan beberapa elemen anak ke atas dan ke bawah di dalam elemen induk. Berfungsi dengan baik untuk memindahkan opsi yang dipilih di listbox (<select multiple></select> )

Pindah ke atas:

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

Turunkan:

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


1

Saya ingin penyihir solusi tidak menggunakan clone () karena memiliki efek samping dengan peristiwa terlampir, inilah yang akhirnya saya lakukan

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

itu tidak boleh digunakan dengan objek jQuery yang mengandung lebih dari satu elemen DOM


1

Jika Anda memiliki banyak salinan dari setiap elemen, Anda perlu melakukan sesuatu dalam satu lingkaran secara alami. Saya mengalami situasi ini baru-baru ini. Dua elemen berulang yang saya butuhkan untuk beralih memiliki kelas dan div kontainer seperti:

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

Kode berikut memungkinkan saya untuk mengulangi semuanya dan membalikkan ...

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

1

Saya telah melakukannya dengan cuplikan ini

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

Saya membuat tabel untuk mengubah urutan objek dalam database yang digunakan .after () .before (), jadi ini dari eksperimen saya.

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

Apakah memasukkan obj1 sebelum obj2 dan

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

lakukan sebaliknya.

Jadi jika obj1 adalah setelah obj3 dan obj2 setelah dari obj4, dan jika Anda ingin mengubah obj1 dan obj2 tempat Anda akan melakukannya seperti

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

Ini harus dilakukan BTW Anda dapat menggunakan .prev () dan .next () untuk menemukan obj3 dan obj4 jika Anda belum memiliki semacam indeks untuk itu.


Bukannya ini hanya ripoff dari jawaban yang diterima, itu berisi kesalahan sintaksis yang buruk. Apakah Anda copypasta ini?
clockw0rk

ehh tidak ?? Ini adalah kode kerja untuk pekerjaan saya di perusahaan saya sebelumnya. Selain itu saya memastikan untuk menunjukkan cara menggunakan dan dalam situasi apa. Mengapa saya perlu merobek seseorang? Saya juga memberi cara mendapatkan indeks objek, itulah sebabnya jawaban yang diterima dikomentari tidak lengkap.
Tran Vu Dang Khoa

lalu mengapa setelah $ () alih-alih setelah ($ ())
clockw0rk

oh ya saya tidak melihatnya, terima kasih. Saya memasukkannya dari memori, tidak memiliki hak untuk menyimpan kode itu setelah saya meninggalkan perusahaan
Tran Vu Dang Khoa

0

jika nodeA dan nodeB adalah saudara kandung, suka dua <tr>sama <tbody>, Anda bisa menggunakan $(trA).insertAfter($(trB))atau $(trA).insertBefore($(trB))menukar mereka, itu berfungsi untuk saya. dan Anda tidak perlu menelepon $(trA).remove()sebelumnya, kalau tidak Anda harus mengikat kembali beberapa acara klik$(trA)


0
$('.five').swap('.two');

Buat fungsi jQuery seperti ini

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

Terima kasih kepada Yannick Guinness di https://jsfiddle.net/ARTsinn/TVjnr/



-2

Saya pikir Anda bisa melakukannya dengan sangat sederhana. Misalnya, Anda memiliki struktur berikut: ...

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

dan hasilnya seharusnya

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

jquery:

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

Saya harap ini membantu!


2
solusi ini sudah ditunjukkan dan tidak berfungsi, kecuali kedua elemen tersebut bersebelahan.
BernaMariano
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.