【问题标题】:Drag Events Only firing once拖动事件仅触发一次
【发布时间】:2016-12-31 19:46:41
【问题描述】:

我正在开发一种带有 HTML5 拖放 API 的益智游戏。我建立了一个 3 行的网格,每行 4 列给我 12 个正方形。除了一个方块之外,所有方块都包含一些从 1 到 11 的数字。空方块是放置区,即可以将任何方块拖入其中。

当一个元素被拖动时,dataTransfer.setData 被设置为被拖动元素的 id,而 ondrop 事件使用 dataTransfer.getData() 获取数据,其结果用于查询被拖动元素的 dom,然后克隆之后,dropzone 现在被克隆节点替换。拖动元素的来源也被替换为 dropzone。

var squares = document.querySelectorAll(".item");
var dropzone = document.querySelector(".col-lg-3.dropzone");

function startDrag(e){
    e.dataTransfer.setData("text", e.target.id);
    console.log(e.target)

}

function overDrag(e){
    e.preventDefault();
    e.target.classList.toggle("dropzone-active");

}

function leaveDrag(e){
    e.preventDefault();
    e.target.classList.toggle("dropzone-active");
}

function dropItem(e){
    e.preventDefault();
    var data = e.dataTransfer.getData("text");
    var draggedElem = document.getElementById(data)
    var clone = draggedElem.cloneNode(true);
    var emptyzone = dropzone.cloneNode(false);
    emptyzone.className = "col-lg-3 dropzone";
    draggedElem.parentNode.replaceChild(emptyzone,draggedElem);

    clone.id = data;
    e.target.parentNode.replaceChild(clone, e.target);
}


for(var i=0; i<squares.length; i++){
    squares[i].addEventListener("dragstart", startDrag, false);
}
dropzone.addEventListener("dragover", overDrag, false);
dropzone.addEventListener("dragleave", leaveDrag, false);
dropzone.addEventListener("drop", dropItem, false);
	#gameZone{
		width:800px;
		height:500px;
		background-color: rgba(0,0,0,.5);
		margin: 0 auto;
		padding:15px;
		position:relative;
	}
	.item,
	.dropzone{
		background-color:red;
		margin-right:10px;
		margin-bottom:15px;
		width:100px;
		height:100px;
		font-size: 2em;
		color:#fff;
		text-align:center;
	}
	.drag-active{
		position:absolute;
		z-index: 10;
	}
	.dropzone-active{
		border:dashed 3px white;
	}

	.dropzone{
		background-color:rgba(255,255,255,.6);
	}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<section id="gameZone">
	<div class="row">
		<div class="col-lg-3 item" id="one" draggable="true">1</div>
		<div class="col-lg-3 item" id="three" draggable="true">3</div>
		<div class="col-lg-3 item" id="two" draggable="true">2</div>
		<div class="col-lg-3 item" id="four" draggable="true">4</div>
	</div>
	<div class="row">
		<div class="col-lg-3 dropzone"></div>
		<div class="col-lg-3 item" id="five" draggable="true">5</div>
		<div class="col-lg-3 item" id="six" draggable="true">6</div>
		<div class="col-lg-3 item" id="nine" draggable="true">9</div>
	</div>
	<div class="row">
		<div class="col-lg-3 item" id="seven" draggable="true">7</div>
		<div class="col-lg-3 item" id="eight" draggable="true">8</div>
		<div class="col-lg-3 item"id="eleven"  draggable="true">11</div>
		<div class="col-lg-3 item" id="ten" draggable="true">10</div>
	</div>
</section>

现在的问题是第一个拖放操作成功了,但是,尝试将新元素拖放到新的 dropzone 中不起作用,它只是无法识别 ondragenter、ondragleave、ondragover 和 drop 事件了。

【问题讨论】:

    标签: javascript html drag-and-drop


    【解决方案1】:

    您可以创建一个函数来设置dropzone 变量,将dragoverdragleavedrop 事件附加到当前dropzone 元素。在drop 事件监听器调用函数中传递data 以将dragstart 事件附加到当前具有id data 的元素。

    var squares = document.querySelectorAll(".item");
    var dropzone;
    
    //= document.querySelector(".col-lg-3.dropzone");
    
    function startDrag(e) {
      e.dataTransfer.setData("text", e.target.id);
    }
    
    function overDrag(e) {
      e.preventDefault();
      e.target.classList.toggle("dropzone-active");
    }
    
    function leaveDrag(e) {
      e.preventDefault();
      e.target.classList.toggle("dropzone-active");
    }
    
    function dropItem(e) {
      e.preventDefault();
      var data = e.dataTransfer.getData("text");
      var draggedElem = document.getElementById(data)
      var clone = draggedElem.cloneNode(true);
      var emptyzone = dropzone.cloneNode(false);
      emptyzone.className = "col-lg-3 dropzone";
      draggedElem.parentNode.replaceChild(emptyzone, draggedElem);
    
      clone.id = data;
      e.target.parentNode.replaceChild(clone, e.target);
      setResetDND(data);
    }
    
    
    for (var i = 0; i < squares.length; i++) {
      squares[i].addEventListener("dragstart", startDrag, false);
    }
    
    function setResetDND(id) {
      dropzone = document.querySelector(".col-lg-3.dropzone");
    
      dropzone.addEventListener("dragover", overDrag, false);
      dropzone.addEventListener("dragleave", leaveDrag, false);
      dropzone.addEventListener("drop", dropItem, false);
      if (id) {
        document.getElementById(id)
        .addEventListener("dragstart", startDrag)
      }
    }
    
    setResetDND();
    #gameZone {
      width: 800px;
      height: 500px;
      background-color: rgba(0, 0, 0, .5);
      margin: 0 auto;
      padding: 15px;
      position: relative;
    }
    .item,
    .dropzone {
      background-color: red;
      margin-right: 10px;
      margin-bottom: 15px;
      width: 100px;
      height: 100px;
      font-size: 2em;
      color: #fff;
      text-align: center;
    }
    .drag-active {
      position: absolute;
      z-index: 10;
    }
    .dropzone-active {
      border: dashed 3px white;
    }
    .dropzone {
      background-color: rgba(255, 255, 255, .6);
    }
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <section id="gameZone">
      <div class="row">
        <div class="col-lg-3 item" id="one" draggable="true">1</div>
        <div class="col-lg-3 item" id="three" draggable="true">3</div>
        <div class="col-lg-3 item" id="two" draggable="true">2</div>
        <div class="col-lg-3 item" id="four" draggable="true">4</div>
      </div>
      <div class="row">
        <div class="col-lg-3 dropzone"></div>
        <div class="col-lg-3 item" id="five" draggable="true">5</div>
        <div class="col-lg-3 item" id="six" draggable="true">6</div>
        <div class="col-lg-3 item" id="nine" draggable="true">9</div>
      </div>
      <div class="row">
        <div class="col-lg-3 item" id="seven" draggable="true">7</div>
        <div class="col-lg-3 item" id="eight" draggable="true">8</div>
        <div class="col-lg-3 item" id="eleven" draggable="true">11</div>
        <div class="col-lg-3 item" id="ten" draggable="true">10</div>
      </div>
    </section>

    【讨论】:

    • 完美。这行得通。但是,我仍然无法理解它为什么/如何工作以及为什么我的代码不起作用。
    • @ibnhamza "现在的问题是第一个拖放操作是成功的,但是,尝试在新的拖放区中拖动一个新元素不起作用,它只是不起作用不再识别 ondragenter、ondragleave、ondragover 和 drop 事件。” 请参阅Node.cloneNode() “克隆节点会复制其所有属性及其值,包括内在(内嵌)侦听器。它不会复制使用 addEventListener() 添加的事件侦听器或分配给元素属性的事件侦听器。"
    • 很好的解释。谢谢
    猜你喜欢
    • 2018-02-26
    • 2023-03-21
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多