как восстановить перемещенный элемент ?

#javascript #html #dom

Вопрос:

 const list = document.querySelector("#List");
const list2 = document.querySelector("#List2");

list.addEventListener("click", (ev) => {
  const LI = ev.target.closest("li");
  list2.append(LI);
});
 
 <ul id="List">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>


<ul id="List2"></ul>
 

этот приведенный выше код в основном переместит <li> элемент в другой <ul> , и я хочу создать функцию, которая восстановит перемещенный <li> обратно в исходный <ul> код в его исходном индексе. так , например, когда я перемещаю этот список <li>3</li> , я хочу, чтобы функция вернула его в исходный индекс в первом <ul> , в этом случае он будет помещен в третий индекс, который находится в середине <li>2</li> и <li>4</li>

как я могу этого достичь?

Комментарии:

1. Что делать, если <li>2</li> он также был перемещен перед восстановлением <li>3</li> ? Что вы пробовали до сих пор? Есть ли фрагмент кода, которым вы можете поделиться с нами?

Ответ №1:

Вот еще один подход. Я обрабатываю все в функции обработчика одного клика. Сначала я «вспоминаю» начальную позицию, которую каждый LI занимал в первом UL . Когда происходит щелчок, я просто переношу LI его в «другое» UL . Затем, если щелчок произошел во втором UL ( if (!idx) ... ), я снова переставляю элементы в первом UL , сортируя их и повторно вставляя в UL .

 const lists = [...document.querySelectorAll("ul.pickable")];
[...lists[0].children].forEach((li,i)=>li.dataset.n=i); // remember original order

document.addEventListener("click", ev => {
  const LI = ev.target.closest("li");
  if (LI?.parentNode.classList.contains("pickable")) { // only, if the click happened within a `LI` element ...
    const idx=lists.indexOf(LI.parentNode),
          UL = lists[1-idx];
    UL.append(LI);
    if (idx) [...UL.children].sort((a,b)=>a.dataset.n-b.dataset.n)
                             .forEach(li=>UL.append(li))
  }
}); 
 <ul class="pickable">
  <li>this</li>
  <li>order</li>
  <li>should</li>
  <li>be</li>
  <li>kept</li>
</ul>


<ul class="pickable"></ul> 

Я мог бы просто опустить, if (idx) если бы хотел LI , чтобы s были отсортированы в обоих UL s в «исходном» порядке.

Ответ №2:

Вам, вероятно, придется запомнить некоторую информацию о том, где вы ее взяли. Есть несколько вариантов:

  • Если вы собираетесь переместить только один li из них, вы можете запомнить его nextSibling элемент, а затем использовать insertBefore в списке, передав эту nextSibling ссылку для «ссылочного элемента». Но если вы также собирались переместить другие элементы, это может не сработать, потому что родного брата после этого может больше не быть.
  • Если вы хотите сделать это по индексу, вам нужно запомнить, какова была позиция элемента в его родительском элементе. Я не думаю, что DOM дает вам прямой способ получить эту информацию, но вы можете найти ее достаточно легко, обратившись Array.prototype.indexOf к родительской children коллекции.
  • Расположите элементы в порядке, который мы можем определить по их содержимому (у них такой порядок в вопросе), и вставьте элемент там, где он должен быть в этом порядке. Не нужно запоминать ничего особенного, потому что оно несет в себе свое содержание.

Вот пример индексного подхода, поскольку вы упомянули об этом в вопросе; см. Комментарии:

 const list = document.querySelector("#List");
const list2 = document.querySelector("#List2");

list.addEventListener("click", (ev) => {
    const li = ev.target.closest("li");
    // Find its index in its parent's `children` collection
    const index = Array.prototype.indexOf.call(li.parentElement.children, li);
    // Save that as an attribute
    li.setAttribute("data-index", index);
    list2.append(li);
});

list2.addEventListener("click", (ev) => {
    const li = ev.target.closest("li");
    // Get the index, if it has one
    let index =  li.getAttribute("data-index");
    // Add at the end if no index or it's out of range
    const maxIndex = list.children.length;
    if (isNaN(index) || index > maxIndex) {
        index = maxIndex;
    }
    // Get the element that will be after it
    const nextSibling = list.children[index] || null;
    // Insert before it (if `nextSibling` is `null`, inserts at the end)
    list.insertBefore(li, nextSibling);
    li.removeAttribute("data-index");
}); 
 <ul id="List">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>

<ul id="List2"></ul> 

Комментарии:

1. Это не всегда работает надежно. Положение каждого LI элемента определяется только при нажатии на него. К тому времени он, возможно, уже переместился на вершину. Пролистайте пример, и вы сами это заметите. (Начните с того, что сначала нажмите на верхние элементы.)

2. @cars10m — Это правда, я не утверждал, что это было все, конец всему; скорее отправная точка. Ваш подход к запоминанию всех начальных индексов является хорошей альтернативой. Я думаю, что если бы я делал это, я бы использовал некоторый естественный порядок элементов, основанный на их содержании (мой третий вариант выше).

3. @cars10m хм, да, я только что понял, что возникнет несколько проблем, если я сделаю это с помощью индексов