Öğeleri değiştirmek için yerel bir jQuery işlevi var mı?


174

JQuery ile iki öğeyi kolayca değiştirebilir miyim?

Mümkünse bunu bir satırla yapmak istiyorum.

Bir seçme öğesi var ve seçenekleri yukarı veya aşağı taşımak için iki düğme var ve zaten seçilmiş ve hedef seçiciler var, bunu bir if ile yapıyorum, ama daha kolay bir yol olup olmadığını merak ediyordum.


İşaretleme ve kod örneği gönderebilir misiniz?
Konstantin Tarkus

Bu jQuery ancak JavaScript meselesi değil: Eğer edemez tek talimatında DOM öğelerini takas. Ancak, [Paolo'nun cevabı] (# 698386) harika bir eklentidir;)
Seb

1
Google'dan buraya gelen insanlar için: çok basit ve benim için mükemmel çalışan lotif'in cevabına göz atın.
Maurice

1
@Maurice, kabul edilen cevabı değiştirdim
juan

1
Bu sadece elemanları birbirinin yanındaysa değiştirir! Lütfen kabul edilen cevabı değiştirin.
Serhiy

Yanıtlar:


233

Ben sadece jQuery kullanarak bu çözmek için ilginç bir yol buldum:

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

veya

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

:)


2
Evet, bu işe yaramalı: Dokümantasyon şöyle diyor: "Bu şekilde seçilen bir eleman başka bir yere yerleştirilirse, hedeften önce taşınır (klonlanmadan)".
12'de Ridcully

12
Bu seçeneği en çok seviyorum! Basit ve güzel uyumlu. Her ne kadar okunabilirlik için el1.insertBefore (el2) ve el1.insertAfter (el2) kullanmak istiyorum.
Maurice

6
Bir sidenote olsa .. (Sanırım bu sayfadaki tüm manipülasyonlar için geçerlidir) DOM burada manipüle. Kaldırdığınız ve eklediğiniz, taşıdığınız öğenin içinde bir iframe varsa iyi çalışmaz. İframe yeniden yüklenir. Ayrıca mevcut URL yerine orijinal URL'sine yeniden yüklenir. Çok can sıkıcı ama güvenlikle ilgili. Bunun için bir çözüm bulamadım
Maurice

202
bu, iki öğe hemen yan yana olmadıkça iki öğeyi değiştirmez.
BonyT

12
Bu artık kabul edilen cevap olmamalıdır. Genelleştirilmiş durumda çalışmaz.
thekingoftruth

79

Paulo haklı, ama neden ilgili unsurları klonladığından emin değilim. Bu gerçekten gerekli değildir ve öğeler ve torunları ile ilişkili referansları veya olay dinleyicilerini kaybeder.

İşte düz DOM yöntemleri kullanan klonlamayan bir sürüm (jQuery'nin bu işlemi kolaylaştırmak için gerçekten özel bir işlevi olmadığından):

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 - "doğru" iletmek de olayları klonlar. İlk önce klonlamadan denedim ama şu anda seninkini yapıyordu: ilkini 2. ile değiştiriyor ve ilkini olduğu gibi bırakıyor.
Paolo Bergantino

<div id = "div1"> 1 </div> <div id = "div2"> 2 </div> varsa ve swapNodes'u (document.getElementById ('div1') çağırırsanız, document.getElementById ('div2') ); i <div id = "div1"> 1 </div> <div id = "div2"> 1 </div>
Paolo Bergantino

3
Ah, a'nın bir sonraki kardeşinin b olduğu bir köşe vakası var. Yukarıdaki kod parçasında düzeltildi. jQuery de aynı şeyi yapıyordu.
bobince

Olayları ve kimlikleri tutması gereken çok hassas bir listeye sahibim ve bu bir cazibe gibi çalışıyor! Teşekkürler!
Teekin

1
Teknik olarak bu sorunun başlığını tatmin etmek için bir jQuery sürümü eklemeniz gerektiğini hissediyorum. :)
thekingoftruth

70

Hayır, yok, ama birini kırbaçlayabilirsiniz:

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

Kullanımı:

$(selector1).swapWith(selector2);

Bunun yalnızca seçicilerin her biri yalnızca 1 öğeyle eşleşmesi durumunda işe yaradığını unutmayın, aksi takdirde garip sonuçlar verebilir.


2
onları klonlamak gerekli mi?
juan

Belki de doğrudan html () kullanarak yazabilirsiniz?
Ed James

2
@Ed Woodcock Eğer yaparsan, o elementler üzerindeki bağlı olayları kaybedeceğinden eminim.
alex

2
Div'ler yan yana olmadığında harika çalışıyor :)
Elmer

Bu kabul edilen cevap olmalı. İsteneni sağlamak için jQuery'yi genişletir.
Alice Wonder

40

Bu soruna, kabul edilen cevap veya bobince'nin cevabı tarafından ele alınmayan çok sayıda uç durum vardır. Klonlamayı içeren diğer çözümler doğru yoldadır, ancak klonlama pahalı ve gereksizdir. İki değişkeni nasıl değiştireceğimize dair asırlık problemi nedeniyle klonlamaya meyilliyiz, buradaki adımlardan biri değişkenlerden birini geçici bir değişkene atamaktır. Bu durumda atamaya (klonlama) gerek yoktur. İşte jQuery tabanlı bir çözüm:

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

7
Bu kabul edilen cevap olmalı. Klonlama olay tetikleyicilerini kaldırır ve gerekli değildir. Kodumda bu kesin yöntemi kullanıyorum.
thekingoftruth

1
Bu daha iyi cevap! Bir jquery sıralanabilir eleman olan takas öğelerimin bir çocuğu olarak ulum var. Paolo Bergantino'nun cevabı ile değiştirdikten sonra liste öğeleri artık atılamadı. User2820356'nın cevabı ile her şey yolunda gitti.
agoldev

20

Bu cevapların birçoğu genel durum için yanlıştır, diğerleri bile çalışırsa gereksiz yere karmaşıktır. JQuery .beforeve .afteryöntemler yapmak istediğiniz şeylerin çoğunu yapar, ancak birçok takas algoritmasının çalışma biçiminde 3. bir öğeye ihtiyacınız vardır. Oldukça basit - bir şeyleri hareket ettirirken yer tutucu olarak geçici bir DOM öğesi yapın. Ebeveynlere veya kardeşlere bakmaya ve kesinlikle klonlamaya gerek yok ...

$.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) tempönce geçici div koymakthis

2) thisönce hareket etthat

3) thatSonra hareket ettemp

3b) kaldır temp

Sonra basitçe

$(selectorA).swapWith(selectorB);

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


2
Bu en iyi cevaptır, diğer tüm unsurlar yan yana. Bu her durumda işe yarar.
brohr

11

İki klona ihtiyacınız yok, biri yapacak. Paolo Bergantino cevabını aldığımızda:

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

Daha hızlı olmalı. İki unsurdan daha küçük olanı geçmek de işleri hızlandırmalıdır.


4
Bu ve Paolo'nun sorunu, kimliklerin benzersiz olması gerektiğinden klonlama işe yaramadığı için bir kimlikle öğeleri değiştirememeleri. Bobince'nin çözümü bu durumda işe yarıyor.
Ruud

Başka bir sorun, olayların copy_to'dan kaldırılmasıdır.
Jan Willem B

8

Daha önce böyle bir teknik kullandım. Http://mybackupbox.com adresindeki bağlayıcı listesi için kullanıyorum

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

bu en iyi çözüm imo, ama end()zincire devam etmiyorsanız buna gerek yok . ne dersin$('element1').clone().before('element2').end().replaceWith('element2');
robisrob

1
just noticed belirtmedikçe clone()herhangi bir jquery korumaz - sıralama yaparsanız önemli bir ayrımdır, böylece tüm verilerinizi kaybetmezsinizdata()clone(true)
robisrob

3

Seçilen birden çok seçeneği yukarı veya aşağı taşımanıza izin veren bir işlev yaptım

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

Bağımlılıklar:

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

İlk olarak, ilk / son seçilen seçeneğin yukarı / aşağı hareket edip edemediğini kontrol eder. Sonra tüm elemanlar ve çağrılar arasında dolaşır

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

Bu, hem kodun yazılma şekli hem de nasıl çalışacağı konusunda verimsizdir.
Blaise

Bu bizim app önemli bir özellik değildi ve ben sadece az miktarda seçenek ile kullanın. Sadece hızlı ve kolay bir şey istedim ... Bunu geliştirebilirsen çok isterdim! Bu harika olurdu!
Tom Maeckelberghe

3

klonlamadan başka bir tane:

Takas için gerçek ve nominal bir eleman var:

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

o zaman insert <div> beforeve removesonradan sadece ihtiyaç duyulursa, her zaman bir elementin var olduğundan emin olamazsınız (benim durumumda)


Ya da sadece .prev()uzunluğunu kontrol edebilirsiniz ve eğer 0, sonra o .prepend()zaman .parent():) Bu şekilde ekstra elemanlar oluşturmanıza gerek kalmaz.
jave.web

2

"Değiştirilebilir" jQuery eklentisine bir göz atın

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

"Sıralanabilir" üzerine kuruludur ve sıralanabilir (sürükle-bırak, yer tutucu vb.) gibi görünür ancak sürüklenen ve bırakılan yalnızca iki öğeyi değiştirir. Diğer tüm öğeler etkilenmez ve mevcut konumlarında kalır.


2

Bu, @lotif'in cevap mantığına dayanan bir cevaptır , ancak biraz daha genelleştirilmiş

Öğeler taşındıktan sonra / sonrasına ekler / başa eklerseniz
=> klonlamaya gerek yoktur
=> olaylar saklanır

Olabilecek iki durum var

  1. Bir hedefte " .prev()ious" => başka bir hedef .after()olabilir.
  2. Bir hedef onun ilk çocuğudur .parent()=> .prepend()diğerini ebeveyn olarak yapabiliriz.

KOD

Bu kod daha kısa yapılabilirdi, ancak okunabilirlik için bu şekilde sakladım. Ebeveynleri (gerekiyorsa) ve önceki öğeleri önceden doldurmanın zorunlu olduğunu unutmayın.

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

});

... iç kodu bir fonksiyona sarmaktan çekinmeyin :)

Örnek kemanın olay korumasını göstermek için ek tıklama olayları eklenmiştir ...
Örnek keman: https://jsfiddle.net/ewroodqa/

... çeşitli durumlarda çalışacak - hatta aşağıdakiler gibi:

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

2

Bu, birden çok alt öğeyi üst öğenin içinde yukarı ve aşağı taşımak için benim çözümüm. Liste kutusundaki seçili seçenekleri taşımak için iyi çalışır ( <select multiple></select>)

Yukarı taşı:

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

Aşağı inmek:

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


1

Bir çözüm cadı, ekli olaylarla yan etkisi olduğu için clone () kullanmıyor, işte sonunda ne yaptım

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

birden fazla DOM öğesi içeren jQuery nesneleriyle kullanılmamalıdır


1

Her öğenin birden fazla kopyası varsa, bir döngüde doğal olarak bir şeyler yapmanız gerekir. Son zamanlarda bu durum vardı. Geçiş yapmak için ihtiyaç duyduğum iki yinelenen öğenin sınıfları ve bir konteyner div vardı:

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

Aşağıdaki kod bana her şeyi yineleme ve tersine izin verdi ...

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

1

Bu pasajla yaptım

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

Ben kullanılan .after () .before (), veritabanında obj sırasını değiştirmek için bir tablo yaptım, bu yüzden bu ne deney var.

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

Obj2'den önce obj1 eklemek ve

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

tam tersini yapın.

Eğer obj1 obj3'den sonra obj3 ve obj2'den sonra ise ve obj1 ve obj2'yi değiştirmek isterseniz,

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

Bunu yapmak için BTW yapmalısınız .prev () ve .next (), obj3 ve obj4'ü bulmak için zaten bir tür dizine sahip değilseniz kullanabilirsiniz.


Bu sadece kabul edilen cevabın bir geri dönüşü değil, kötü bir sözdizimsel hata içeriyor. Bunu kopyaladın mı?
clockw0rk

ha hayır! Bu benim önceki şirketteki işlerim için çalışma kodu. Yanında nasıl kullanılacağını ve hangi durumda işaret ettiğinden emin oldum. Neden birini sökmem gerekiyor? Ayrıca nesne indeksinin nasıl alınacağını da veriyorum, bu yüzden kabul edilen cevap tamamlanmadı olarak yorumlandı.
Tran Vu Dang Khoa

o zaman neden sonra ($ ()) yerine $ () 'dan sonra
clockw0rk

oh evet görmedim, teşekkürler. Bellekten girdim, şirketten ayrıldıktan sonra bu kodu saklamaya hakkım yok
Tran Vu Dang Khoa

0

nodeA ve nodeB kardeş ise, ikisi <tr>aynıdır <tbody>, bunları kullanabilir $(trA).insertAfter($(trB))veya $(trA).insertBefore($(trB))değiştirebilirsiniz, benim için işe yarıyor. ve daha $(trA).remove()önce aramanıza gerek yoktur , aksi takdirde bazı tıklama etkinliklerini yeniden bağlamanız gerekir$(trA)


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

Bunun gibi bir jQuery işlevi oluşturun

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

Sayesinde Yannick Guinness at https://jsfiddle.net/ARTsinn/TVjnr/



-2

Bence bunu çok basit yapabilirsin. Diyelim ki bir sonraki yapınız var: ...

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

ve sonuç olmalı

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

jQuery:

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

Umut ediyorum bu yardım eder!


2
bu çözüm zaten belirtilmişti ve iki unsur hemen yan yana olmadıkça işe yaramıyor.
BernaMariano
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.