요소를 전환하는 기본 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> beforeremove당신이 확인하지 못할 경우 이후에만 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.