Поменять местами два горизонтально выровненных элемента div

У меня есть следующие элементы DOM на одной горизонтальной линии:

  1. div, содержащий строку текста; то есть «Привет, мир». Ширина этого div такая же, как и содержащего его текста.
  2. Кнопка, чтобы поменять местами два div.
  3. Div, содержащий список. Ширина этого div такая же, как у содержащего списка.

С помощью float или position:absolute я могу правильно выровнять эти элементы на одной строке. Однако, когда пользователь нажимает кнопку переключения, элементы div должны поменяться местами. Я бы предпочел не удалять элементы div из DOM и снова добавлять их друг на друга. Это потому, что элементы на самом деле являются объектами Javascript (точнее, компонентами Google Closure Library), которые содержат переменные и имеют прикрепленные к ним обработчики событий. Можно ли поменять местами div с помощью CSS, не назначая статическую ширину div?

Упрощенный пример:

<div style="position:relative; height:60px;">
  <div style="float:left;">Our Team</div>
  <div style="float:left;"><button onclick="swap();">swap home/away</button></div>
  <div style="float:left;"><select><option>Opponent A</option><option>Opponent B</option></select></div>
</div>
<div style="clear:both;"></div>

Когда пользователь нажимает кнопку, первый (наша команда) и третий (противник) div должны визуально поменяться местами в браузере, желательно без удаления элементов из DOM.


person Korneel    schedule 26.11.2012    source источник
comment
покажите нам свой код, как вы точно реализуете вещи..........   -  person Shailender Arora    schedule 26.11.2012
comment
@ShailenderArora Я добавил упрощенную версию HTML-кода.   -  person Korneel    schedule 26.11.2012


Ответы (3)


Я бы предпочел не удалять элементы div из DOM и снова добавлять их друг на друга. Это потому, что элементы на самом деле являются объектами Javascript (точнее, компонентами Google Closure Library), которые содержат переменные и имеют прикрепленные к ним обработчики событий.

Лучшее решение — вместо этого переместить элементы в DOM. Это сохранит существующие обработчики событий, а это значит, что ваш код все еще должен работать:

http://jsfiddle.net/thirtydot/LGGW2/

function swap() {
    var target1 = document.querySelector('#swapMe > :first-child');
    var target2 = document.querySelector('#swapMe > :last-child');

    var parent = target1.parentNode;
    parent.insertBefore(target1, null);
    parent.insertBefore(target2, parent.firstChild);
}​

Я предполагаю, что у вас уже есть ссылка на элементы, которые вы хотите поменять местами, поэтому вы можете заменить строки document.querySelector любым подходящим.

После написания этого ответа я искал более общую функцию «своп» и нашел это, которое выглядит хорошо: Поменять местами 2 элемента html и сохранить в них прослушиватели событий

person thirtydot    schedule 26.11.2012
comment
Это действительно лучшее решение. Благодарю вас! - person Korneel; 26.11.2012

В вашем HTML оба div одинаковы (style="float:left;"), нет class или id, поэтому вы можете поменять местами только HTML обоих div, т.е.

function swap(e)
{
    e  = e || window.event, target = e.target || e.srcElement;
    var nEl=getElem(target.parentNode, 'next');
    var pEl=getElem(target.parentNode, 'prev');
    var pElHtml=pEl.innerHTML, nElHtml=nEl.innerHTML;
    pEl.innerHTML=nElHtml;
    nEl.innerHTML=pElHtml;
}

function getElem(elem, which) {
    if(which==='next') which='nextSibling';
    else if((which==='prev')) which='previousSibling'; 
    do{
        elem = elem[which];
    }
    while (elem && elem.nodeType != 1);
    return elem;        
}​

ДЕМО.

person The Alpha    schedule 26.11.2012
comment
К сожалению, это испортит связанные события. Нажмите «Наша команда», затем нажмите «Обмен», затем снова нажмите «Наша команда»: jsfiddle.net/thirtydot/Wxp9j/1 - person thirtydot; 26.11.2012
comment
@thirtydot, вы совершенно правы, но я думал, что такого события не бывает, поэтому ответил так, но еще раз спасибо и +1. - person The Alpha; 26.11.2012

У меня есть несколько решений вашей проблемы. Один или два связаны с вашим стилем. На вашем месте я бы удалил встроенные стили (если они не добавлены javascript) и добавил бы один и тот же класс ко всем «плавающим» элементам.

Для более обновленных браузеров это будет работать отлично:

.floaters{
    display:inline-block;
}

Но для более старых браузеров (например, 5.5, 6, 7, 8) вам нужно будет применить:

.floaters{
    display:inline;
    float:left;
    height:60px;/*set a default height*/
}

теперь для функции swap();. Я не уверен, как вы применяете это, но я бы поменял местами элементы, изменив их innerHTML();

function swap(){
    var ele1HTML = document.getElementById('ele1').innerHTML();
    var ele3HTML = document.getElementById('ele3').innerHTML();
    document.getElementById('ele1').innerHTML(ele3HTML);
    document.getElementById('ele3').innerHTML(ele1HTML);
}

Но следующий код потребует, чтобы вы добавили атрибуты ID в свои div. Вот пример:

<div id="menu">
  <div id="ele1" class="floater">
      Our Team
  </div>
  <div id="ele2" class="floater">
      <button onclick="swap();">swap home/away</button>
  </div>
  <div id="ele3" class="floater">
      <select>
          <option>Opponent A</option>
          <option>Opponent B</option>
      </select>
  </div>
</div>
<div id="anotherDiv"></div>

Но не забудьте повторно применить свои стили:

#menu{
    position:relative;
    height:60px; /*not needed for the older browser as I've set the child elements to 60px;*/
}
#anotherDiv{
    clear:both;
}
person bashleigh    schedule 26.11.2012
comment
Итак, вы хотите поменять местами элементы только один раз? или изменить html внутри кнопки? - person bashleigh; 26.11.2012
comment
@Beneto Каждый раз, когда пользователь нажимает кнопку, элементы меняются местами. Сами элементы и элементы внутри них не могут быть удалены из DOM, потому что к ним прикреплены/могут быть прикреплены обработчики событий. В памяти клиента переменные связаны с этими элементами DOM. Если вы удалите innerHTML такого элемента, вам придется переназначать эти переменные и обработчики событий при каждом свопинге. Кроме того, я не использую встроенные стили в своем производственном коде, но это более лаконичный способ показать здесь код. - person Korneel; 26.11.2012
comment
@Korneel О да, я не думал о том, что просто меняю местами дочерние элементы, никогда не думал о том, чтобы их запускать. - person bashleigh; 26.11.2012