Có một hàm jQuery gốc để chuyển đổi các phần tử không?


174

Tôi có thể dễ dàng trao đổi hai phần tử với jQuery không?

Tôi đang tìm cách để làm điều này với một dòng nếu có thể.

Tôi có một yếu tố được chọn và tôi có hai nút để di chuyển lên hoặc xuống các tùy chọn và tôi đã có sẵn các bộ chọn đích và chọn, tôi làm điều đó với một if, nhưng tôi tự hỏi liệu có cách nào dễ dàng hơn không.


Bạn có thể gửi cho bạn đánh dấu và mẫu mã?
Konstantin Tarkus

Đây không phải là vấn đề của jQuery mà là JavaScript: bạn không thể trao đổi các phần tử DOM trong một lệnh. Tuy nhiên, [câu trả lời của Paolo] (# 698386) là một plugin tuyệt vời;)
Seb

1
Đối với những người đến đây từ google: hãy xem câu trả lời của lotif, rất đơn giản và hoàn toàn phù hợp với tôi.
Maurice

1
@Maurice, tôi đã thay đổi câu trả lời được chấp nhận
juan

1
Điều này chỉ hoán đổi các yếu tố nếu chúng ở cạnh nhau! Xin vui lòng, thay đổi câu trả lời được chấp nhận.
Serhiy

Câu trả lời:


233

Tôi đã tìm thấy một cách thú vị để giải quyết vấn đề này chỉ bằng jQuery:

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

hoặc là

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

:)


2
Vâng, điều này sẽ hoạt động: Tài liệu nói: "Nếu một yếu tố được chọn theo cách này được chèn vào nơi khác, nó sẽ được di chuyển trước mục tiêu (không được nhân bản)".
Vô lý

12
Tôi thích tùy chọn này là tốt nhất! Đơn giản và tương thích độc đáo. Mặc dù tôi thích sử dụng el1.insertB Before (el2) và el1.insertAfter (el2) để dễ đọc.
Maurice

6
Một sidenote mặc dù .. (mà tôi đoán áp dụng cho tất cả các giải pháp trên trang này) vì chúng tôi đang thao túng DOM ở đây. Xóa và thêm không hoạt động tốt khi có iframe hiện diện trong phần tử bạn đang di chuyển. Khung nội tuyến sẽ tải lại. Ngoài ra, nó sẽ tải lại url gốc thay vì url hiện tại. Rất phiền phức nhưng liên quan đến an ninh. Tôi chưa tìm thấy giải pháp nào cho việc này
Maurice

202
điều này không trao đổi hai yếu tố trừ khi hai yếu tố ngay lập tức nằm cạnh nhau.
BonyT

12
Đây không phải là câu trả lời được chấp nhận nữa. Nó không hoạt động trong trường hợp tổng quát.
thekingoftruth

79

Paulo nói đúng, nhưng tôi không chắc tại sao anh ta nhân bản các yếu tố liên quan. Điều này không thực sự cần thiết và sẽ mất bất kỳ tài liệu tham khảo hoặc người nghe sự kiện nào liên quan đến các yếu tố và con cháu của họ.

Đây là phiên bản không nhân bản bằng các phương thức DOM đơn giản (vì jQuery không thực sự có bất kỳ chức năng đặc biệt nào để giúp thao tác cụ thể này dễ dàng hơn):

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 - cũng chuyển nó thành "sự thật". Tôi đã cố gắng mà không nhân bản nó trước nhưng nó đang làm những gì hiện tại của bạn: đó là trao đổi cái đầu tiên với cái thứ hai và để lại cái đầu tiên.
Paolo Bergantino

if i ); tôi nhận được <div id = "div1"> 1 </ div> <div id = "div2"> 1 </ div>
Paolo Bergantino

3
À, có một trường hợp góc mà anh chị em tiếp theo là b. Đã sửa lỗi trong đoạn trích trên. jQuery đã làm điều tương tự chính xác.
bobince

Tôi có một danh sách rất nhạy cảm theo thứ tự cần giữ lại các sự kiện và ID và điều này hoạt động như một cơ duyên! Cảm ơn!
Teekin

1
Tôi cảm thấy như thể bạn nên thêm một phiên bản jQuery để đáp ứng về mặt kỹ thuật cho tiêu đề của câu hỏi này. :)
thekingoftruth

70

Không, không có, nhưng bạn có thể đánh một cái:

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

Sử dụng:

$(selector1).swapWith(selector2);

Lưu ý điều này chỉ hoạt động nếu các bộ chọn chỉ khớp với 1 phần tử mỗi phần, nếu không nó có thể cho kết quả lạ.


2
Có cần thiết phải nhân bản chúng?
juan

Có lẽ bạn có thể viết chúng trực tiếp bằng html ()?
Ed James

2
@Ed Woodcock Nếu bạn làm thế, bạn sẽ mất các sự kiện bị ràng buộc trên các yếu tố đó tôi khá chắc chắn.
alex

2
Hoạt động tuyệt vời khi các div không ở cạnh nhau :)
Elmer

Đây phải là câu trả lời được chấp nhận. Nó mở rộng jQuery để cung cấp những gì được yêu cầu.
Alice Wonder

40

Có rất nhiều trường hợp cạnh tranh cho vấn đề này, không được xử lý bởi câu trả lời được chấp nhận hoặc câu trả lời của bobince. Các giải pháp khác liên quan đến nhân bản đang đi đúng hướng, nhưng nhân bản là tốn kém và không cần thiết. Chúng tôi muốn sao chép, vì vấn đề muôn thuở là làm thế nào để hoán đổi hai biến, trong đó một trong các bước là gán một trong các biến cho biến tạm thời. Việc chuyển nhượng, (nhân bản), trong trường hợp này là không cần thiết. Đây là một giải pháp dựa trên jQuery:

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

7
Đây phải là câu trả lời được chấp nhận. Nhân bản loại bỏ bất kỳ kích hoạt sự kiện và không cần thiết. Tôi sử dụng phương pháp chính xác này trong mã của tôi.
thekingoftruth

1
Đây là câu trả lời tốt hơn! Tôi rất vui khi có một ul như một đứa trẻ của các yếu tố hoán đổi của tôi, đó là một yếu tố sắp xếp jquery. Sau khi hoán đổi với câu trả lời của Paolo Bergantino, các mục trong danh sách không thể bỏ được nữa. Với câu trả lời của user2820356, mọi thứ vẫn hoạt động tốt.
agoldev

20

Nhiều câu trả lời đơn giản là sai đối với trường hợp chung, những câu trả lời khác phức tạp không cần thiết nếu thực tế chúng thậm chí còn hoạt động. JQuery .before.aftercác phương thức thực hiện hầu hết những gì bạn muốn làm, nhưng bạn cần một phần tử thứ 3 theo cách mà nhiều thuật toán trao đổi hoạt động. Điều này khá đơn giản - tạo một phần tử DOM tạm thời làm trình giữ chỗ trong khi bạn di chuyển mọi thứ xung quanh. Không cần phải nhìn vào cha mẹ hay anh chị em, và chắc chắn không cần phải nhân bản ...

$.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) đặt div tạm thời temptrướcthis

2) di chuyển thistrướcthat

3) di chuyển that sautemp

3b) xóa temp

Sau đó, đơn giản

$(selectorA).swapWith(selectorB);

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


2
Đây là câu trả lời tốt nhất, tất cả những người khác đều cho rằng các yếu tố nằm cạnh nhau. Điều này hoạt động trong mọi tình huống.
brohr

11

Bạn không cần hai bản sao, một sẽ làm. Lấy câu trả lời của Paolo Bergantino chúng ta có:

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

Nên nhanh hơn. Đi qua trong hai yếu tố nhỏ hơn cũng sẽ tăng tốc mọi thứ.


4
Vấn đề với điều này, và của Paolo, là họ không thể trao đổi các yếu tố với ID vì ID phải là duy nhất để nhân bản không hoạt động. Giải pháp của Bobince không hoạt động trong trường hợp này.
Ruud

Một vấn đề khác là điều này sẽ loại bỏ các sự kiện từ copy_to.
Jan Willem B

8

Tôi đã sử dụng một kỹ thuật như thế này trước đây. Tôi sử dụng nó cho danh sách kết nối trên 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');

Đây là giải pháp tốt nhất, nhưng không cần thiết end()nếu bạn không tiếp tục chuỗi. làm thế nào về$('element1').clone().before('element2').end().replaceWith('element2');
robisrob

1
chỉ cần chú ý clone()không lưu giữ bất kỳ trò đùa nào data()trừ khi bạn chỉ định clone(true) - một sự khác biệt quan trọng nếu bạn sắp xếp để bạn không bị mất tất cả dữ liệu của mình
robisrob

3

Tôi đã tạo một chức năng cho phép bạn di chuyển nhiều tùy chọn đã chọn lên hoặc xuống

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

Phụ thuộc:

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

Đầu tiên, nó kiểm tra xem tùy chọn được chọn đầu tiên / cuối cùng có thể di chuyển lên / xuống hay không. Sau đó, nó lặp qua tất cả các yếu tố và các cuộc gọi

exchangeWith (Element.next () hoặc 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);
}

Điều này là không hiệu quả, cả về cách viết mã và cách thức thực hiện.
Blaise

Đây không phải là một tính năng chính của ứng dụng của chúng tôi và tôi chỉ sử dụng nó với một số lượng nhỏ các tùy chọn. Tôi chỉ muốn một cái gì đó nhanh chóng và dễ dàng ... Tôi sẽ thích nó nếu bạn có thể cải thiện điều này! Điều đó sẽ rất tuyệt!
Tom Maeckelberghe

3

một cái khác mà không nhân bản:

Tôi có một yếu tố thực tế và danh nghĩa để trao đổi:

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

sau đó insert <div> beforeremovesau đó chỉ cần thiết, nếu bạn không thể đảm bảo, luôn có một yếu tố trước (trong trường hợp của tôi là vậy)


Hoặc bạn chỉ có thể kiểm tra .prev()độ dài và nếu 0, sau đó .prepend()đến .parent():) Bằng cách đó, bạn không cần phải tạo thêm các yếu tố.
jave.web

2

hãy xem plugin jQuery "Swapable"

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

nó được xây dựng trên "Sắp xếp" và trông giống như có thể sắp xếp (kéo thả, giữ chỗ, v.v.) nhưng chỉ trao đổi hai yếu tố: kéo và thả. Tất cả các yếu tố khác không bị ảnh hưởng và ở trên vị trí hiện tại của họ.


2

Đây là câu trả lời dựa trên @lotif logic câu trả lời của , nhưng khái quát hơn một chút

Nếu bạn chắp thêm / trả trước sau / trước khi các phần tử thực sự được di chuyển
=> không cần sao chép
=> các sự kiện được giữ

Có hai trường hợp có thể xảy ra

  1. Một mục tiêu có cái gì đó " .prev()ious" => chúng ta có thể đặt mục tiêu khác .after()đó.
  2. Một mục tiêu là con đầu tiên của nó .parent()=> chúng ta có thể .prepend()nhắm mục tiêu khác vào cha mẹ.

Mật mã

Mã này có thể được thực hiện thậm chí ngắn hơn, nhưng tôi giữ nó theo cách này để dễ đọc. Lưu ý rằng cha mẹ uy tín (nếu cần) và các yếu tố trước đó là bắt buộc.

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

});

... hãy thoải mái bọc mã bên trong trong một hàm :)

Ví dụ fiddle có thêm các sự kiện nhấp chuột kèm theo để thể hiện bảo toàn sự kiện ...
Ví dụ fiddle: https://jsfiddle.net/ewroodqa/

... sẽ hoạt động cho nhiều trường hợp khác nhau - thậm chí một trường hợp như:

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

2

Đây là giải pháp của tôi để di chuyển nhiều phần tử con lên xuống trong phần tử cha. Hoạt động tốt để di chuyển các tùy chọn đã chọn trong listbox ( <select multiple></select>)

Đi lên:

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

Đi xuống:

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


1

Tôi muốn một phù thủy giải pháp không sử dụng clone () vì nó có tác dụng phụ với các sự kiện đính kèm, đây là những gì tôi đã là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;
};

không được sử dụng với các đối tượng jQuery chứa nhiều phần tử DOM


1

Nếu bạn có nhiều bản sao của mỗi yếu tố, bạn cần phải làm một cái gì đó trong một vòng lặp một cách tự nhiên. Tôi đã có tình huống này gần đây. Hai phần tử lặp lại mà tôi cần để chuyển đổi có các lớp và một div container như vậy:

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

Đoạn mã sau cho phép tôi lặp lại mọi thứ và đảo ngược ...

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

1

Tôi đã thực hiện nó với đoạn trích này

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

Tôi đã làm một bảng để thay đổi thứ tự obj trong cơ sở dữ liệu được sử dụng .after () .b Before (), vì vậy đây là từ những gì tôi đã thử nghiệm.

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

Được chèn obj1 trước obj2 và

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

làm ngược lại.

Vì vậy, nếu obj1 là sau obj3 và obj2 sau obj4, và nếu bạn muốn thay đổi vị trí obj1 và obj2, bạn sẽ làm như thế

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

Điều này sẽ làm điều đó BTW, bạn có thể sử dụng .prev () và .next () để tìm obj3 và obj4 nếu bạn chưa có một loại chỉ mục nào cho nó.


Đây không phải là một sự lột xác của câu trả lời được chấp nhận, nó chứa một lỗi cú pháp xấu. Bạn đã copypasta này?
clockw0rk

hả Đây là mã làm việc cho công việc của tôi tại công ty trước đây của tôi. Bên cạnh tôi chắc chắn chỉ ra cách sử dụng và trong tình huống nào. Tại sao tôi cần phải xé toạc một ai đó? Tôi cũng đưa ra cách lấy chỉ mục của đối tượng, đó là lý do tại sao câu trả lời được chấp nhận được nhận xét là chưa hoàn thành.
Trần Vũ Đăng Khoa

vậy thì tại sao nó lại sau $ () thay vì sau ($ ())
clockw0rk

oh yeah tôi đã không nhìn thấy nó, cảm ơn. Tôi nhập nó từ bộ nhớ, không có quyền giữ mã đó sau khi tôi rời công ty
Trần Vũ Đăng Khoa

0

nếu nodeA và nodeB là anh em ruột, thích hai <tr>cái giống nhau <tbody>, bạn chỉ cần sử dụng $(trA).insertAfter($(trB))hoặc $(trA).insertBefore($(trB))trao đổi chúng, nó hoạt động với tôi. và bạn không cần phải gọi $(trA).remove()trước, nếu không bạn cần phải liên kết lại một số sự kiện nhấp chuột trên$(trA)


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

Tạo một hàm jQuery như thế này

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

Cảm ơn Yannick Guinness tại https://jsfiddle.net/ARTsinn/TVjnr/



-2

Tôi nghĩ bạn có thể làm điều đó rất đơn giản. Ví dụ: giả sử bạn có cấu trúc tiếp theo: ...

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

và kết quả phải là

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

jquery:

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

Tôi hy vọng nó sẽ giúp!


2
giải pháp này đã được chỉ ra và không hoạt động, trừ khi hai yếu tố ngay lập tức nằm cạnh nhau.
BernaMariano
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.