JavaScript 可排序列表中的拖放问题

Drag and Drop Issue in JavaScript Sortable List

提问人:lukas95 提问时间:8/27/2023 最后编辑:lukas95 更新时间:8/27/2023 访问量:96

问:

大家好,这是我在这里的第一个问题:

我目前正在开发一个 Web 应用程序,该应用程序涉及在单独的列表中对项目进行拖放排序。我有两个不同的列表:左边列表和右边列表。目标是使用户能够使用拖放功能对每个列表中的项目进行重新排序。

我已经成功地在每个单独的列表中实现了拖放排序。但是,在将项目从左侧列表拖到右侧列表时,我遇到了意外行为。具体来说,当我从左侧列表中拖动一个项目并将其拖放到右侧列表中的项目上时,右侧列表中项目的位置似乎被交换了。

我正在寻求有关如何防止在将左侧列表中的项目拖放到右侧列表中的项目时受到影响的指导。理想情况下,我希望保持对每个列表中的项目进行独立排序的能力,同时确保从一个列表中拖动一个项目不会影响另一个列表的排序。

此外,如果您能建议我的代码是否可以更干净、更易读,我们将不胜感激。

欢迎任何评论

提前致谢

我尝试删除事件侦听器并再次添加它们,但没有帮助。

const grid = document.querySelector('.grid');
const leftDiv = document.querySelector('.left-side')
const rightDiv = document.querySelector('.right-side')

const pairs = [
    {pol: 'jeden', eng: 'one'},
     {pol: 'dwa', eng: 'two'},
     {pol: 'trzy', eng: 'three'},
     {pol: 'cztery', eng: 'four'},
     {pol: 'piec', eng: 'five'},
    ]

    

    

const leftList = [];
const rightList = [];
let leftElement;


createList();

function createList() {
    const leftSide = [...pairs]
        .map(a => ({ value: a.pol, sort: Math.random() }))
        .sort((a, b) => a.sort - b.sort)
        .map(a => a.value)
        .forEach((item, index) => {

            leftElement = document.createElement('div');
            leftElement.setAttribute('data-index', index);
            leftElement.setAttribute('data-left', true);
            

            leftElement.innerHTML = `
                                    <div class="draggable left-draggable" draggable="true"  data-left="true">
                                        <p class="item-name">${item}</p>
                                    </div>
                                     `;
            leftDiv.appendChild(leftElement);

            leftList.push(leftElement)

        });

        const rightSide = [...pairs]
        .map(a => ({ value: a.eng, sort: Math.random() }))
        .sort((a, b) => a.sort - b.sort)
        .map(a => a.value)
        .forEach((item, index) => {

           const rightElement = document.createElement('div');
            rightElement.setAttribute('data-index', index);
            rightElement.setAttribute('data-right', true);
            

            rightElement.innerHTML = `
                                    <div class="draggable right-draggable" draggable="true" data-right="true">
                                        <p class="item-name">${item}</p>
                                    </div>
                                        `;

            rightDiv.appendChild(rightElement)

            rightList.push(rightElement)

        })

        addEventListener();
}




function addEventListener() {
    document.querySelectorAll('.draggable').forEach((item, index) =>{
        item.addEventListener('dragstart', dragStart);
    });

    document.querySelectorAll('[data-index]').forEach(item => {
        item.addEventListener('dragenter', dragEnter);
        item.addEventListener('dragleave', dragLeave);
        item.addEventListener('dragover', dragOver);
        item.addEventListener('drop', dragDrop);
        
    })
    
}

let dragStartIndex;

function dragStart(e) {
    

    if(e.target.getAttribute('data-left')){
    
        dragStartIndex = +this.closest('[data-index]').getAttribute('data-index');
    
        
    } else if(e.target.getAttribute('data-right')){
        
        dragStartIndex = +this.closest('[data-index]').getAttribute('data-index');
    
    }
     
}

function dragEnter() {
    
}
function dragLeave() {
   
}
function dragOver(e) {
    e.preventDefault();
   
}
function dragDrop(e) {   
    
    

    if(e.target.closest('[data-right]')){
       
        const dragEndIndex = +this.closest('[data-index]').getAttribute('data-index');
        console.log(dragEndIndex);
        swapItems(dragStartIndex, dragEndIndex, 'right');
        

    } else if(e.target.closest('[data-left]')){
        
        const dragEndIndex = +this.closest('[data-index]').getAttribute('data-index');
        console.log(dragEndIndex);
        swapItems(dragStartIndex, dragEndIndex, 'left');
    }

   
}


function swapItems(fromIndex, toIndex, data) {
    
   

    if(data === 'right' ){
        
        const itemOne = rightList[fromIndex].querySelector('.right-draggable');
        const itemTwo = rightList[toIndex].querySelector('.right-draggable');
            if(itemOne.getAttribute('data-right') && itemTwo.getAttribute('data-right')){
                rightList[fromIndex].appendChild(itemTwo)
                rightList[toIndex].appendChild(itemOne)
            } 
        
    } else if(data === 'left') {
    
        
        const itemOne = leftList[fromIndex].querySelector('.left-draggable');
        const itemTwo = leftList[toIndex].querySelector('.left-draggable');
            if(itemOne.getAttribute('data-left') && itemTwo.getAttribute('data-left')){
                leftList[fromIndex].appendChild(itemTwo)
                leftList[toIndex].appendChild(itemOne)
            }
        
    }
}











   
*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

.grid {
    display: flex;
    margin: 50px auto;
    width: 500px;
    justify-content: center;
    /* gap: 30px; */
}

div[data-index] {
    padding: 25px;
    border: solid 2px #333;
    
}

.item-name {
    font-size: 25px;
    font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
    text-transform: uppercase;
    padding: 10px 20px;
    border: 2px solid #ccc;
    border-radius: 16px;
    text-align: center;
    cursor: pointer;
    
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="grid">
        <div class="left-side"></div>
        <div class="right-side"></div>
    </div>

    <script src="main.js"></script>
</body>
</html>

JavaScript的 列表 排序 拖放

评论

0赞 IT goldman 8/27/2023
从一个列表拖动到另一个列表时的预期行为是什么?

答:

0赞 IT goldman 8/27/2023 #1

然后,您需要在拖动开始时注意这是哪一边。现在,您需要做的就是检查拖动何时结束,如果目标确实是预期的目标。

const grid = document.querySelector('.grid');
const leftDiv = document.querySelector('.left-side')
const rightDiv = document.querySelector('.right-side')

const pairs = [{
    pol: 'jeden',
    eng: 'one'
  },
  {
    pol: 'dwa',
    eng: 'two'
  },
  {
    pol: 'trzy',
    eng: 'three'
  },
  {
    pol: 'cztery',
    eng: 'four'
  },
  {
    pol: 'piec',
    eng: 'five'
  },
]

const leftList = [];
const rightList = [];
let leftElement;

createList();

function createList() {
  const leftSide = [...pairs]
    .map(a => ({
      value: a.pol,
      sort: Math.random()
    }))
    .sort((a, b) => a.sort - b.sort)
    .map(a => a.value)
    .forEach((item, index) => {

      leftElement = document.createElement('div');
      leftElement.setAttribute('data-index', index);
      leftElement.setAttribute('data-left', true);

      leftElement.innerHTML = `<div class="draggable left-draggable" draggable="true"  data-left="true"><p class="item-name">${item}</p></div>`;
      leftDiv.appendChild(leftElement);

      leftList.push(leftElement)

    });

  const rightSide = [...pairs]
    .map(a => ({
      value: a.eng,
      sort: Math.random()
    }))
    .sort((a, b) => a.sort - b.sort)
    .map(a => a.value)
    .forEach((item, index) => {

      const rightElement = document.createElement('div');
      rightElement.setAttribute('data-index', index);
      rightElement.setAttribute('data-right', true);

      rightElement.innerHTML = `<div class="draggable right-draggable" draggable="true" data-right="true"><p class="item-name">${item}</p></div>`;

      rightDiv.appendChild(rightElement)

      rightList.push(rightElement)

    })

  addEventListener();
}


function addEventListener() {
  document.querySelectorAll('.draggable').forEach((item, index) => {
    item.addEventListener('dragstart', dragStart);
  });

  document.querySelectorAll('[data-index]').forEach(item => {
    item.addEventListener('dragenter', dragEnter);
    item.addEventListener('dragleave', dragLeave);
    item.addEventListener('dragover', dragOver);
    item.addEventListener('drop', dragDrop);
  })

}

let dragStartIndex;

// I've add a variable that is set when drag start and checked when drag end
let dragOrigin;

function dragStart(e) {

  if (e.target.getAttribute('data-left')) {

    dragStartIndex = +this.closest('[data-index]').getAttribute('data-index');
    dragOrigin = "left"

  } else if (e.target.getAttribute('data-right')) {

    dragOrigin = "right"
    dragStartIndex = +this.closest('[data-index]').getAttribute('data-index');

  }

}

function dragEnter() {}

function dragLeave() {}

function dragOver(e) {
  e.preventDefault();

}

function dragDrop(e) {

  if (e.target.closest('[data-right]')) {

    if (dragOrigin != "right") {
      console.log("denied")
      return
    }
    const dragEndIndex = +this.closest('[data-index]').getAttribute('data-index');
    console.log(dragEndIndex);
    swapItems(dragStartIndex, dragEndIndex, 'right');


  } else if (e.target.closest('[data-left]')) {

    if (dragOrigin != "left") {
      console.log("denied")
      return
    }

    const dragEndIndex = +this.closest('[data-index]').getAttribute('data-index');
    console.log(dragEndIndex);
    swapItems(dragStartIndex, dragEndIndex, 'left');
  }

}

function swapItems(fromIndex, toIndex, data) {

  if (data === 'right') {

    const itemOne = rightList[fromIndex].querySelector('.right-draggable');
    const itemTwo = rightList[toIndex].querySelector('.right-draggable');
    if (itemOne.getAttribute('data-right') && itemTwo.getAttribute('data-right')) {
      rightList[fromIndex].appendChild(itemTwo)
      rightList[toIndex].appendChild(itemOne)
    }

  } else if (data === 'left') {

    const itemOne = leftList[fromIndex].querySelector('.left-draggable');
    const itemTwo = leftList[toIndex].querySelector('.left-draggable');
    if (itemOne.getAttribute('data-left') && itemTwo.getAttribute('data-left')) {
      leftList[fromIndex].appendChild(itemTwo)
      leftList[toIndex].appendChild(itemOne)
    }

  }
}
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.grid {
  display: flex;
  margin: 20px auto;
  width: 300px;
  justify-content: center;
  /* gap: 30px; */
}

div[data-index] {
  padding: 10px;
  border: solid 2px #333;
}

.item-name {
  font-size: 15px;
  font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
  text-transform: uppercase;
  padding: 5px 10px;
  border: 2px solid #ccc;
  border-radius: 16px;
  text-align: center;
  cursor: pointer;
}
<div class="grid">
  <div class="left-side"></div>
  <div class="right-side"></div>
</div>