HTML5 中的多个放置事件

发布于 2024-11-24 07:25:53 字数 2947 浏览 1 评论 0原文

我正在尝试在 HTML5 中创建拖放功能,我可以从一个列表拖动到另一个列表。我有一个包含可拖动项目的列表,另一个包含添加了放置事件的项目的列表。问题是,无论我放到哪个元素上,最后添加的放置事件都会被调用。

感谢您的任何帮助或建议。

我在下面包含了我的代码:

<!DOCTYPE html>

<head>
<title>List Conversion Test</title>

<style type="text/css">

#list, #cart {
  display: inline;
  float: left;
  border: 1px solid #444;
  margin: 25px;
  padding: 10px;
}

#list p {
  background-color: #036;
  color: #fff;
}
#cart p {
  background-color: #363;
  color: #fff;
}

.listitem {

}

.listitem_done {
  text-decoration: line-through;
}

.product {
  background-color: #CCC;
}

.product_over {
  background-color: #363;
}

</style>


<script type="text/javascript" src="http://html5demos.com/js/h5utils.js"></script>

</head>

<body>

<article>
  <div id="list">
    <p>On My List</p>
    <ul>
      <li class="listitem" id="L001">Shopping List Item #1</li>
      <li class="listitem" id="L002">Shopping List Item #2</li>
    </ul>
    <div id="done">
      <p>In My Cart</p>
      <ul></ul>
    </div>
  </div>

  <div id="cart">
    <p>Cart</p>
    <ul>
      <li class="product" id="P001">Product #1</li>
      <li class="product" id="P002">Product #2</li>
    </ul>
  </div>

</article>
<script>

  // make list items draggable
  var list = document.querySelectorAll('li.listitem'), thisItem = null;
  for (var i = 0; i < list.length; i++) {
    thisItem = list[i];

    thisItem.setAttribute('draggable', 'true');

    addEvent(thisItem, 'dragstart', function (e) {
      e.dataTransfer.effectAllowed = 'copy';
      e.dataTransfer.setData('Text', this.id);
    });
  }


  // give products drop events
  var products = document.querySelectorAll('li.product'), thisProduct = null;
  for (var i = 0; i < products.length; i++) {
    thisProduct = products[i];

    addEvent(thisProduct, 'dragover', function (e) {
      if (e.preventDefault) e.preventDefault();
      this.className = 'product_over';
      e.dataTransfer.dropEffect = 'copy';
      return false;
    });

    addEvent(thisProduct, 'dragleave', function () {
     this.className = 'product';
    });

    addEvent(thisProduct, 'drop', function (e) {
      //alert(thisProduct.id);
      if (e.stopPropagation) e.stopPropagation();
      var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
      thisItem.parentNode.removeChild(thisItem);
      thisProduct.className = 'product';
      handleDrop(thisItem, thisProduct);
      return false;
    });

  }

  // handle the drop
  function handleDrop(i, p) {
    alert(i.id + ' to ' + p.id);
    var done = document.querySelector('#done > ul');
    done.appendChild(i);
    i.className = 'listitem_done';
  } 


</script>

</body>
</html>

I'm trying to create a drag and drop feature in HTML5 where I can drag from one list to another. I have one list with draggable items and another list with items that have drop events added. The problem is, regardless of what element I drop onto, the last drop event that was added is the one that gets called.

Thanks for any help or suggestions.

I've included my code below:

<!DOCTYPE html>

<head>
<title>List Conversion Test</title>

<style type="text/css">

#list, #cart {
  display: inline;
  float: left;
  border: 1px solid #444;
  margin: 25px;
  padding: 10px;
}

#list p {
  background-color: #036;
  color: #fff;
}
#cart p {
  background-color: #363;
  color: #fff;
}

.listitem {

}

.listitem_done {
  text-decoration: line-through;
}

.product {
  background-color: #CCC;
}

.product_over {
  background-color: #363;
}

</style>


<script type="text/javascript" src="http://html5demos.com/js/h5utils.js"></script>

</head>

<body>

<article>
  <div id="list">
    <p>On My List</p>
    <ul>
      <li class="listitem" id="L001">Shopping List Item #1</li>
      <li class="listitem" id="L002">Shopping List Item #2</li>
    </ul>
    <div id="done">
      <p>In My Cart</p>
      <ul></ul>
    </div>
  </div>

  <div id="cart">
    <p>Cart</p>
    <ul>
      <li class="product" id="P001">Product #1</li>
      <li class="product" id="P002">Product #2</li>
    </ul>
  </div>

</article>
<script>

  // make list items draggable
  var list = document.querySelectorAll('li.listitem'), thisItem = null;
  for (var i = 0; i < list.length; i++) {
    thisItem = list[i];

    thisItem.setAttribute('draggable', 'true');

    addEvent(thisItem, 'dragstart', function (e) {
      e.dataTransfer.effectAllowed = 'copy';
      e.dataTransfer.setData('Text', this.id);
    });
  }


  // give products drop events
  var products = document.querySelectorAll('li.product'), thisProduct = null;
  for (var i = 0; i < products.length; i++) {
    thisProduct = products[i];

    addEvent(thisProduct, 'dragover', function (e) {
      if (e.preventDefault) e.preventDefault();
      this.className = 'product_over';
      e.dataTransfer.dropEffect = 'copy';
      return false;
    });

    addEvent(thisProduct, 'dragleave', function () {
     this.className = 'product';
    });

    addEvent(thisProduct, 'drop', function (e) {
      //alert(thisProduct.id);
      if (e.stopPropagation) e.stopPropagation();
      var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
      thisItem.parentNode.removeChild(thisItem);
      thisProduct.className = 'product';
      handleDrop(thisItem, thisProduct);
      return false;
    });

  }

  // handle the drop
  function handleDrop(i, p) {
    alert(i.id + ' to ' + p.id);
    var done = document.querySelector('#done > ul');
    done.appendChild(i);
    i.className = 'listitem_done';
  } 


</script>

</body>
</html>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

桜花祭 2024-12-01 07:25:53

这就是为什么在循环中定义函数(例如回调函数)通常是一个坏主意。您在循环内分配 thisProduct,但它将在循环的下一次迭代中重新分配。按照闭包的设置方式,每个回调都绑定到同一个变量 thisProduct,并且将使用最新值。

一种可能的修复方法是在需要 thisProduct 的地方创建一个新的闭包,例如

(function(thisProduct) {
    addEvent(thisProduct, 'drop', function (e) {
      //alert(thisProduct.id);
      if (e.stopPropagation) e.stopPropagation();
      var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
      thisItem.parentNode.removeChild(thisItem);
      thisProduct.className = 'product';
      handleDrop(thisItem, thisProduct);
      return false;
    });
}(thisProduct));

This jsFiddle似乎现在对我有用。请参阅此处了解更多说明。

This is why it's often a bad idea to define functions (such as callback functions) within a loop. You're assigning thisProduct within the loop, but it will be reassigned for the next iteration of the loop. The way your closures are set up, each callback is bound to the same variable thisProduct, and will use the latest value.

One possible fix is to create a new closure where thisProduct is needed such as

(function(thisProduct) {
    addEvent(thisProduct, 'drop', function (e) {
      //alert(thisProduct.id);
      if (e.stopPropagation) e.stopPropagation();
      var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
      thisItem.parentNode.removeChild(thisItem);
      thisProduct.className = 'product';
      handleDrop(thisItem, thisProduct);
      return false;
    });
}(thisProduct));

This jsFiddle seems to work for me now. See here for more explanation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文