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.

juan
sumber
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"));

:)

lotif
sumber
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);
}
bobince
sumber
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.

Paolo Bergantino
sumber
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);
};
pengguna2820356
sumber
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

Robisrob
sumber
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.

Matthew Wilcoxson
sumber
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');
Eric Warnke
sumber
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);
}
Tom Maeckelberghe
sumber
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)

setengah bit
sumber
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.

vadimk
sumber
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>
jave.web
sumber
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"));
});
pistipanko
sumber
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

Mistic
sumber
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"));
});
AdamJones
sumber
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();
zveljkovic
sumber
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.

Tran Vu Dang Khoa
sumber
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)

Spark.Bao
sumber
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/

Airy
sumber
-2

Pilihan terbaik adalah mengklona mereka dengan metode clone ().

pengguna84771
sumber
1
ini menghilangkan callback dan binding apa pun
thekingoftruth
-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!

Jernej Gololicic
sumber
2
solusi ini sudah ditunjukkan dan tidak berfungsi, kecuali kedua elemen tersebut bersebelahan.
BernaMariano