拖放在动态创建的列表上无法正常工作

huangapple go评论65阅读模式
英文:

Drag and drop not functioning on dynamically created list

问题

我有一个由JavaScript动态生成的活动列表,如下所示:

const renderList = (activities) => {
  const display = document.getElementById('task-list-display');
  activities.forEach((activity) => {
    console.log(activity);
    display.insertAdjacentHTML('beforeend', ` 
    <li class="task-item draggable" draggable="true">
      <div class="chk-descr">
        <input data-a1="${activity.index}" type="checkbox" name="completed"/>
        <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
      </div>
    </li> 
    `);
  });
};

我希望使其具有响应性,以便可以使用拖放进行重新排列。然而,我无法使其正常工作。以前我设计了完全相同的应用程序,但是与使用insertAdjacentHTML()插入列表项不同,我是使用createElement()创建每个元素,然后使用appendChild()将其附加到相应的HTML元素中。那个应用程序上的拖放功能是正常的。我的问题是:是否有某些原因导致使用insertAdjacentHTML动态生成的列表无法进行拖放?

以下是所有相关代码:

let activities = [];

const dragstart = (element) => {
  element.classList.add('skateover');
};

const dragover = (element, e) => {
  e.preventDefault();
  element.classList.add('dragover');
};

const dragleave = (element) => {
  element.classList.remove('dragover');
};

const drop = (element) => {
  const skateover = document.querySelector('.skateover');
  element.before(skateover);

  repopulateList();
  element.classList.remove('dragover');
};

const dragend = (element) => {
  element.classList.remove('skateover');
};

const repopulateList = () => {
  const listItems = document.querySelectorAll('.draggable');
  emptyList();

  let i = 0;
  listItems.forEach((listItem) => {
    listItem.setAttribute('activity', i);
    i += 1;
    
    const description = listItem.getElementsByClassName('description')[0].textContent;
    const completed = listItem.getElementsByClassName('completed')[0].checked;
    const index = listItem.getAttribute('activity');

    inputActivity(description, completed, index);
  });
};

const inputActivity = (description, completed, index) => {
  activities.push({ description, completed, index: parseInt(index, 10) });
};

在HTML文件中:

<ul id="task-list-display"></ul>
英文:

I have a list of activities that is generated dynamically with javascript in the following manner:

const renderList = (activities) =&gt; {
  const display = document.getElementById(&#39;task-list-display&#39;);
  activities.forEach((activity) =&gt; {
    console.log(activity);
    display.insertAdjacentHTML(&#39;beforeend&#39;, ` 
    &lt;li class=&quot;task-item draggable&quot; draggable=&quot;true&quot;&gt;
      &lt;div class=&quot;chk-descr&quot;&gt;
        &lt;input data-a1=&quot;${activity.index}&quot; type=&quot;checkbox&quot; name=&quot;completed&quot;/&gt;
        &lt;p data-b1=&quot;${activity.index}&quot; class=&quot;description&quot; contenteditable=&quot;true&quot;&gt;${activity.description}&lt;/p&gt;
      &lt;/div&gt;
    &lt;/li&gt; 
    `);

I want to have it be responsive in a way that the items can be rearranged using drag and drop. I am not able, however, to make this work. Previously I had designed the very same app but instead of having the items of the list be inserted using insertAdjacentHTML() I was creating each element using createElement() and then appending it to the corresponding HTML element using appendChild(). The drag and drop functionality on that app was fully functioning. My question is: is there some reason why drag and drop might not work with a dynamically generated list using insertAdjacentHTML?.

Here is all the relevant code:

let activities = [];

const dragstart = (element) =&gt; {
  element.classList.add(&#39;skateover&#39;);
};

const dragover = (element, e) =&gt; {
  e.preventDefault();
  element.classList.add(&#39;dragover&#39;);
};

const dragleave = (element) =&gt; {
  element.classList.remove(&#39;dragover&#39;);
};

const drop = (element) =&gt; {
  const skateover = document.querySelector(&#39;.skateover&#39;);
  element.before(skateover);

  repopulateList();
  element.classList.remove(&#39;dragover&#39;);
};

const dragend = (element) =&gt; {
  element.classList.remove(&#39;skateover&#39;);
};

const repopulateList = () =&gt; {
  const listItems = document.querySelectorAll(&#39;.draggable&#39;);
  emptyList();

  let i = 0;
  listItems.forEach((listItem) =&gt; {
    listItem.setAttribute(&#39;activity&#39;, i);
    i += 1;
    
    const description = listItem.getElementsByClassName(&#39;description&#39;)[0].textContent;
    const completed = listItem.getElementsByClassName(&#39;completed&#39;)[0].checked;
    const index = listItem.getAttribute(&#39;activity&#39;);

    inputActivity(description, completed, index);
  });
};

const inputActivity = (description, completed, index) =&gt; {
  activities.push({ description, completed, index: parseInt(index, 10) });
};

And in the HTML file:

&lt;ul id=&quot;task-list-display&quot;&gt;&lt;/ul&gt;

答案1

得分: 1

这不是问题。在这里,我将事件监听器添加到无序列表(<ul>)中。因此,添加、克隆和移除列表项(<li>)不是问题。

在使用诸如 insertAdjacentHTML() 这样的方法时没有问题。在这个示例中,我只是使用 cloneNode() 来克隆移动的节点,然后使用 insertBefore() 将克隆的节点插入到鼠标悬停/放置的列表项之前。

const aktivities = [{
    index: 1,
    description: "Item 1"
  },
  {
    index: 2,
    description: "Item 2"
  },
  {
    index: 3,
    description: "Item 3"
  }
];

const display = document.getElementById('task-list-display');

const renderList = (activities) => {
  activities.forEach((activity) => {
    display.insertAdjacentHTML('beforeend', ` 
    <li class="task-item draggable" draggable="true" data-id="${activity.index}">
      <div class="chk-descr">
        <input data-a1="${activity.index}" type="checkbox" name="completed"/>
        <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
      </div>
    </li> 
    `)
  });
};

display.addEventListener("dragstart", e => {
  e.dataTransfer.setData("text/plain", e.target.dataset.id);
});

display.addEventListener("dragover", e => {
  e.preventDefault();
  [...display.querySelectorAll('li')].forEach(li => li.classList.remove('over'));
  e.target.closest('li.task-item').classList.add('over');
});

display.addEventListener("drop", e => {
  e.preventDefault();
  [...display.querySelectorAll('li')].forEach(li => li.classList.remove('over'));
  let original = document.querySelector(`li[data-id="${e.dataTransfer.getData("text/plain")}"]`);
  let clone = original.cloneNode(true);
  let target = e.target.closest('li.task-item');
  display.insertBefore(clone, target);
  display.removeChild(original);
});

renderList(aktivities);
ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li div {
  display: flex;
  flex-direction: row;
}

.over {
  border-top: solid thin black;
}
<ul id="task-list-display"></ul>
英文:

That is not a problem. Here I add the eventlisteners to the unordered list (&lt;ul&gt;). So, the adding, cloning and removing of list items (&lt;li&gt;) is not an issue.

There is no problem in using methods like insertAdjacentHTML(). In this example I just use cloneNode() for cloning the node that is moved and then insertBefore() to insert the cloned node before the list item that is hovered/dropped on.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const aktivities = [{
index: 1,
description: &quot;Item 1&quot;
},
{
index: 2,
description: &quot;Item 2&quot;
},
{
index: 3,
description: &quot;Item 3&quot;
}
];
const display = document.getElementById(&#39;task-list-display&#39;);
const renderList = (activities) =&gt; {
activities.forEach((activity) =&gt; {
display.insertAdjacentHTML(&#39;beforeend&#39;, ` 
&lt;li class=&quot;task-item draggable&quot; draggable=&quot;true&quot; data-id=&quot;${activity.index}&quot;&gt;
&lt;div class=&quot;chk-descr&quot;&gt;
&lt;input data-a1=&quot;${activity.index}&quot; type=&quot;checkbox&quot; name=&quot;completed&quot;/&gt;
&lt;p data-b1=&quot;${activity.index}&quot; class=&quot;description&quot; contenteditable=&quot;true&quot;&gt;${activity.description}&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt; 
`)
});
};
display.addEventListener(&quot;dragstart&quot;, e =&gt; {
e.dataTransfer.setData(&quot;text/plain&quot;, e.target.dataset.id);
});
display.addEventListener(&quot;dragover&quot;, e =&gt; {
e.preventDefault();
[...display.querySelectorAll(&#39;li&#39;)].forEach(li =&gt; li.classList.remove(&#39;over&#39;));
e.target.closest(&#39;li.task-item&#39;).classList.add(&#39;over&#39;);
});
display.addEventListener(&quot;drop&quot;, e =&gt; {
e.preventDefault();
[...display.querySelectorAll(&#39;li&#39;)].forEach(li =&gt; li.classList.remove(&#39;over&#39;));
let original = document.querySelector(`li[data-id=&quot;${e.dataTransfer.getData(&quot;text/plain&quot;)}&quot;]`);
let clone = original.cloneNode(true);
let target = e.target.closest(&#39;li.task-item&#39;);
display.insertBefore(clone, target);
display.removeChild(original);
});
renderList(aktivities);

<!-- language: lang-css -->

ul {
margin: 0;
padding: 0;
list-style: none;
}
li div {
display: flex;
flex-direction: row;
}
.over {
border-top: solid thin black;
}

<!-- language: lang-html -->

&lt;ul id=&quot;task-list-display&quot;&gt;&lt;/ul&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月2日 00:28:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76383962.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定