Ответ 1
Я нашел интересный способ решить эту проблему, используя только jQuery:
$("#element1").before($("#element2"));
или
$("#element1").after($("#element2"));
:)
Можно ли легко заменить два элемента с помощью jQuery?
Я хочу сделать это с одной строкой, если это возможно.
У меня есть элемент select, и у меня есть две кнопки для перемещения вверх или вниз по параметрам, и у меня уже есть выбранные и целевые селекторы на месте, я делаю это с if, но мне было интересно, есть ли путь.
Я нашел интересный способ решить эту проблему, используя только jQuery:
$("#element1").before($("#element2"));
или
$("#element1").after($("#element2"));
:)
Пауло прав, но я не уверен, почему он клонирует элементы. Это действительно не обязательно и потеряет любые ссылки или прослушиватели событий, связанные с элементами и их потомками.
Здесь используется некланирующая версия, использующая простые методы 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);
}
Нет, нет, но вы можете взломать один:
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);
Обратите внимание, что это работает только в том случае, если селекторы соответствуют только одному элементу, иначе это может дать странные результаты.
В этой проблеме есть много краевых случаев, которые не обрабатываются принятым ответом или bobince. Другие решения, связанные с клонированием, находятся на правильном пути, но клонирование является дорогостоящим и ненужным. Мы испытываем соблазн клонировать из-за давней проблемы о том, как заменить две переменные, в которой одним из шагов является присвоение одной из переменных временной переменной. Назначение (клонирование) в этом случае не требуется. Вот решение на основе jQuery:
function swap(a, b) {
a = $(a); b = $(b);
var tmp = $('<span>').hide();
a.before(tmp);
b.before(a);
tmp.replaceWith(b);
};
Вам не нужны два клона, один будет делать. Отвечая на вопрос Паоло Бергантино, мы имеем:
jQuery.fn.swapWith = function(to) {
return this.each(function() {
var copy_to = $(to).clone(true);
$(to).replaceWith(this);
$(this).replaceWith(copy_to);
});
};
Быть быстрее. Передача в меньшем из двух элементов также должна ускорить процесс.
Многие из этих ответов просто неправильны для общего случая, другие излишне сложны, если они на самом деле даже работают. Методы 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://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 place
$('element1').replaceWith('element2');
Я создал функцию, которая позволяет перемещать несколько выбранных параметров вверх или вниз
$('#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);
}
другой без клонирования:
У меня есть фактический и номинальный элемент для обмена:
$nominal.before('<div />')
$nb=$nominal.prev()
$nominal.insertAfter($actual)
$actual.insertAfter($nb)
$nb.remove()
then insert <div> before
и remove
после этого нужны только, если вы не можете гарантировать, что всегда есть элемент forfor (в моем случае это)
Взгляните на плагин jQuery "Swapable"
http://code.google.com/p/jquery-swapable/
он построен на "Sortable" и выглядит как сортируемый (drag-n-drop, placeholder и т.д.), но только обменивает два элемента: перетаскивается и отбрасывается. Все остальные элементы не затронуты и остаются на их текущем положении.
Это ответ, основанный на логике ответа @lotif, но бит более обобщенный
Если вы добавляете/добавляете после/до того, как элементы на самом деле перемещены
= > нет необходимости клонирования
= > сохраненные события
.prev()
ious" = > мы можем поставить другую цель .after()
..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>
Это мое решение для перемещения нескольких дочерних элементов вверх и вниз внутри родительского элемента. Хорошо работает для перемещения выбранных параметров в списке (<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"));
});
Если вы хотите поменять два элемента, выбранных в объекте jQuery, вы можете использовать этот метод
Я хотел, чтобы решение witch не использовало 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;
};
он не должен использоваться с объектами jQuery, содержащими более одного элемента DOM
Если у вас есть несколько копий каждого элемента, вам нужно что-то сделать в цикле естественным образом. У меня была эта ситуация недавно. Два повторяющихся элемента, которые мне нужно было переключить, имели классы и контейнер 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"));
});
Я сделал это с помощью этого фрагмента
// 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();
Я сделал таблицу для изменения порядка obj в используемой базе данных .after().before(), так что это от того, что у меня есть.
$(obj1).after$(obj2)
Вставляет obj1 перед obj2 и
$(obj1).before$(obj2)
делать наоборот.
Итак, если obj1 после obj3 и obj2 после obj4, и если вы хотите изменить место obj1 и obj2, вы сделаете это как
$(obj1).before$(obj4)
$(obj2).before$(obj3)
Это должно сделать это BTW вы можете использовать .prev() и .next(), чтобы найти obj3 и obj4, если у вас уже не был какой-то индекс для него.
Если nodeA и nodeB являются братьями и сестрами, ему нравится два <tr>
в том же <tbody>
, вы можете просто использовать $(trA).insertAfter($(trB))
или $(trA).insertBefore($(trB))
для их замены, это работает для меня. и вам не нужно вызывать $(trA).remove()
раньше, иначе вам нужно повторно привязать некоторые события кликов на $(trA)
Лучший вариант - клонировать их методом clone().
Я думаю, вы можете сделать это очень просто. Например, скажем, у вас есть следующая структура: ...
<div id="first">...</div>
<div id="second">...</div>
и результат должен быть
<div id="second">...</div>
<div id="first">...</div>
JQuery
$('#second').after($('#first'));
Надеюсь, это поможет!