요소를 전환하는 기본 jQuery 함수가 있습니까?


174

두 요소를 jQuery와 쉽게 교체 할 수 있습니까?

가능한 경우 한 줄 로이 작업을 수행하려고합니다.

선택 요소가 있고 옵션을 위 또는 아래로 이동하는 두 개의 버튼이 있으며 이미 선택된 대상 선택기가 있고 if와 함께 사용하지만 if로 수행하지만 더 쉬운 방법이 있는지 궁금합니다.


마크 업 및 코드 샘플을 게시 할 수 있습니까?
— Konstantin Tarkus

jQuery가 아니라 JavaScript의 문제입니다 . 단일 명령으로 DOM 요소를 교체 할 수 없습니다 . 그러나 [Paolo 's answer] (# 698386)은 훌륭한 플러그인입니다.)
— Seb

1
Google에서 여기 온 사람들의 경우 : lotif의 답변을 확인하십시오. 매우 간단하고 완벽하게 작동했습니다.
— Maurice

1
@Maurice, 나는 대답을 바꾸었다
— juan

1
서로 옆에있는 경우에만 요소를 바꿉니다! 수락 된 답변을 변경하십시오.
— Serhiy

답변:


233

jQuery 만 사용하여이를 해결하는 흥미로운 방법을 찾았습니다.

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

또는

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

:)


2
예, 다음과 같이 작동합니다. 설명서에 "이 방법으로 선택한 요소를 다른 곳에 삽입하면 대상이 복제되지 않은 상태로 이동됩니다"라고 말합니다.
— Ridcully

12
이 옵션이 가장 좋습니다! 간단하고 훌륭하게 호환됩니다. 가독성을 위해 el1.insertBefore (el2) 및 el1.insertAfter (el2)를 사용하고 싶습니다.
— Maurice

6
그러나 여기서는 DOM을 조작하기 때문에 한 쪽의 참고 사항입니다. (이 페이지의 모든 솔루션에 적용되는 것 같습니다.) 이동중인 요소 내에 iframe이 있으면 제거 및 추가가 제대로 작동하지 않습니다. iframe이 새로 고침됩니다. 또한 현재 URL 대신 원래 URL로 다시로드됩니다. 매우 성가 시지만 보안 관련. 이에 대한 해결책을 찾지 못했습니다
— Maurice

202
두 요소가 서로 바로 옆에 있지 않으면 두 요소를 교체하지 않습니다.
— BonyT

12
더 이상 허용되는 답변이 아니어야합니다. 일반적인 경우에는 작동하지 않습니다.
— thekingoftruth

79

Paulo는 옳지 만 왜 그가 관련 요소를 복제하고 있는지 잘 모르겠습니다. 이것은 꼭 필요한 것은 아니며 요소 및 하위 요소와 관련된 참조 또는 이벤트 리스너를 잃게됩니다.

다음은 일반 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"로 전달하면 이벤트도 복제됩니다. 나는 그것을 먼저 복제하지 않고 시도했지만 현재 당신의 일을하고 있었다 : 그것은 첫 번째 것을 두 번째 것으로 바꾸고 첫 번째 것을 그대로 둡니다.
— Paolo Bergantino 2016 년

<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>을
— 받음

3
아, 다음 형제가 b 그 자체 인 코너 케이스가 있습니다. 위의 스 니펫에서 수정되었습니다. jQuery는 똑같은 일을하고있었습니다.
— bobince 2014 년

나는 이벤트와 ID를 유지 해야하는 매우 민감한 주문 목록을 가지고 있으며 이것은 매력처럼 작동합니다! 감사!
— Teekin

1
이 질문의 제목을 기술적으로 만족시키기 위해 jQuery 버전을 추가해야한다고 생각합니다. :)
— thekingoftruth

70

아니요, 없습니다.하지만 채찍을 채울 수 있습니다.

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

셀렉터가 하나의 요소 만 일치하는 경우에만 작동합니다. 그렇지 않으면 이상한 결과가 발생할 수 있습니다.


2
복제해야합니까?
— juan

html ()을 사용하여 직접 작성할 수 있습니까?
— Ed James

2
@Ed Woodcock 만약 그렇게한다면, 당신은 그 요소에 대한 바운드 이벤트를 잃을 것입니다.
— alex

2
div가 서로 옆에 있지 않을 때 잘 작동합니다 :)
— Elmer

이것이 정답입니다. 요청 된 내용을 제공하기 위해 jQuery를 확장합니다.
— Alice Wonder

40

이 문제에는 많은 경우가 있으며, 허용되는 답변이나 bobince의 답변으로 처리되지 않습니다. 복제와 관련된 다른 솔루션은 올바른 길을 가고 있지만 복제는 비싸고 불필요합니다. 변수 중 하나를 임시 변수에 할당하는 단계 중 하나 인 두 변수를 교체하는 방법에 대한 오래된 문제로 인해 복제하려고합니다. 이 경우 할당 (복제)이 필요하지 않습니다. 다음은 jQuery 기반 솔루션입니다.

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

7
이것이 정답입니다. 복제는 모든 이벤트 트리거를 제거하며 필요하지 않습니다. 내 코드 에서이 정확한 방법을 사용합니다.
— thekingoftruth

1
이것이 더 나은 대답입니다! 교체 된 요소의 자식으로 ul이 발생했습니다. 이는 jquery 정렬 가능 요소였습니다. Paolo Bergantino의 답변으로 바꾸고 나면 목록 항목을 더 이상 삭제할 수 없습니다. user2820356의 답변으로 모든 것이 여전히 잘 작동했습니다.
— agoldev

20

이러한 답변 중 많은 부분이 일반적인 경우에 잘못되었으며, 실제로 작동하는 경우에는 불필요하게 복잡합니다. jQuery .before와 .after메소드는 대부분의 작업을 수행하지만 많은 스왑 알고리즘이 작동하는 방식으로 세 번째 요소가 필요합니다. 아주 간단합니다. 사물을 옮기는 동안 임시 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

두 개의 클론이 필요하지 않아야합니다. 파올로 베르 간 티노의 대답은 다음과 같습니다.

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

더 빨라야합니다. 두 요소 중 작은 요소를 전달하면 속도가 빨라집니다.


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

이것은 최고의 솔루션 imo이지만 end()체인을 계속 하지 않으면 필요 하지 않습니다. 방법에 대한$('element1').clone().before('element2').end().replaceWith('element2');
— robisrob

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

코드 작성 방식과 수행 방식면에서 비효율적입니다.
— Blaise

그것은 우리 앱의 주요 기능이 아니며 소량의 옵션으로 사용합니다. 나는 단지 빠르고 쉬운 것을 원했습니다 ... 이것을 향상시킬 수 있다면 그것을 좋아할 것입니다! 대단 할 것입니다!
— Tom Maeckelberghe

3

복제하지 않은 다른 것 :

교환 할 실제 및 공칭 요소가 있습니다.

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

다음 insert <div> before과 remove당신이 확인하지 못할 경우 이후에만 befor를 요소가 (내 경우에는) 항상 있다는 것을, 필요


아니면 그냥 확인 할 수 .prev()의 길이, 0 경우, 다음 .prepend()에 .parent(): 그런 식으로 당신은 여분의 요소를 만들 필요가 없습니다.
— jave.web

2

jQuery 플러그인 "Swapable"살펴보기

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

"Sortable"을 기반으로하며 정렬 가능 (드래그 앤 드롭, 플레이스 홀더 등)처럼 보이지만 드래그 앤 드롭이라는 두 가지 요소 만 교환합니다. 다른 모든 요소는 영향을받지 않으며 현재 위치를 유지합니다.


2

이것은 @lotif 의 답변 논리를 기반으로 한 답변 이지만 좀 더 일반화되었습니다.

요소를 실제로 이동 한 후 / 앞에 추가 / 앞에 추가하는 경우
=> 복제 필요 없음
=> 이벤트 유지

발생할 수있는 두 가지 경우가 있습니다

  1. 한 목표는 " .prev()ious"=> 다른 목표를 .after()가질 수 있습니다.
  2. 하나의 목표는 그것의 첫 번째 자식입니다. .parent()=> 우리는 .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

각 요소의 사본이 여러 개인 경우 루프에서 자연스럽게 무언가를 수행해야합니다. 나는 최근에 이런 상황을 겪었다. 전환해야 할 두 가지 반복 요소에는 클래스와 컨테이너 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이 obj4 이후에 obj3 및 obj2 뒤에 있고 obj1 및 obj2 장소를 변경하려면 다음과 같이하십시오.

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

BTW를 수행해야합니다. .prev () 및 .next ()를 사용하여 이미 색인이없는 경우 obj3 및 obj4를 찾을 수 있습니다.


이것은 단지 받아 들여진 답변의 요약이 아니라 잘못된 구문 오류를 포함합니다. 이것을 복사하여 붙여 넣었습니까?
— clockw0rk

아니 아니 ?? 이것은 이전 회사에서 일한 작업 코드입니다. 옆에 나는 사용 방법과 상황을 지적했다. 왜 누군가를 찢어 야합니까? 또한 객체의 색인을 얻는 방법을 제공하므로 수락 된 답변이 완료되지 않은 것으로 설명되었습니다.
— Tran Vu Dang Khoa

그렇다면 왜 after ($ ()) 대신 after $ ()
— 입니까?

오 예, 그것을 보지 못했습니다, 감사합니다. 나는 그것을 메모리에서 입력했다, 내가 회사를 떠난 후에 그 코드를 유지할 권리가 없다
— Tran Vu Dang Khoa

0

nodeA와 nodeB가 형제이고 같은 두 개 <tr>를 좋아 <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

-2

나는 당신이 그것을 매우 간단하게 할 수 있다고 생각합니다. 예를 들어 다음 구조가 있다고 가정 해 봅시다. ...

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

결과는

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

jquery :

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

도움이 되길 바랍니다!


2
이 솔루션은 이미 지적되었으며 두 요소가 서로 바로 옆에 있지 않으면 작동하지 않습니다.
— BernaMariano
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.