Javascript Drag and Drop Hover Временный элемент Div Заполнитель похож на Trello? - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть базовая трэллоподобная канбан доска.Вы можете перетаскивать задачи между различными серыми полями.Он использует HTML-интерфейс перетаскивания, найденный здесь https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API.

var dropTarget = document.querySelector(".drop-target");
var draggables = document.querySelectorAll(".drag-task");

// Tells the other side what data is being passed (e.g. the ID is targeted)
draggables.forEach(item => {
  item.addEventListener("dragstart", function(ev){
    ev.dataTransfer.setData("srcId", ev.target.id);
  });
})
// The end destination, prevent browsers default drag and drop (disabling breaks feature)
// because it's disabled by browsers by default
dropTarget.addEventListener('dragover', function(ev) {
  ev.preventDefault();
});
// End destination where item is dropped into
dropTarget.addEventListener('drop', function(ev) {
  ev.preventDefault();
  let target = ev.target;
  let droppable  = target.classList.contains('drag-box');
  let srcId = ev.dataTransfer.getData("srcId");

  if (droppable) {
    ev.target.appendChild(document.getElementById(srcId));
  }
});
/***********DRAGGABLE BACKGROUND ****************/
.drag-box {
  background-color: lightgray;
  float: right;
  width: 120px;
  min-height: 50px;
  padding-bottom: 30px;
  height: auto;
  margin: 30px;
}
.drag-task {
  background-color: white;
  margin: 15px;
}
.drop-active {
  border: 1px dashed red;
}
<div class="drop-target">
    <div class="drag-box">
      <div class="drag-card">
        <div draggable="true" id="task1" class="drag-task">Test Card 1</div>
      </div>
      <div class="drag-card">
        <div draggable="true" id="task2" class="drag-task">Test Card 2</div>
      </div>
      <div class="drag-card">
        <div draggable="true" id="task3" class="drag-task">Test Card 3</div>
      </div>
    </div>
    <div class="drag-box">
    </div>
    <div class="drag-box">
    </div>
  </div>

Я хочу добиться эффекта, похожего на этот гиф, найденный здесь .Это создает еще один элемент <div> на том же уровне, что и класс drag-card для эффекта перетаскивания, и соответствующим образом перемещается.

enter image description here

Я знаю, что яЯ должен использовать dragover и dragleave прослушиватели событий, но это насколько я понял.Я добавил этот код в конец файла.Я никогда не использовал прослушиватели событий перетаскивания, так что для меня это ново.

var makeHoverElement= true;
dropTarget.addEventListener("dragover", function(ev){
  if(makeHoverElement){
    let newNode =document.createElement('div');
    newNode.className ='drop-active'
    ev.target.parentElement.prepend(newNode);
    makeHoverElement = false;
  }
});

dropTarget.addEventListener("dragleave", function(ev){
   // really I have no idea how to make this effect
});

Результаты пока не оправдались, как я ожидал.Dragover применяется к элементу, в котором элемент task произошел от

enter image description here

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Проблема в ev.target.parentElement.prepend(newNode); Ваш ev.target все еще является потомком узла, который вы перетаскиваете из .Вот почему пунктирная граница div добавляется в «старое» поле.Я полагаю, что в вашей функции 'dragover' вы явно находите элемент, над которым находится мышь, и добавляете в него свой новый узел.Например, вы можете выбрать его с помощью document.querySelector(":hover" ) или попытаться обработать события 'mouseover'.

Что касается эффекта 'dragleave', я предлагаю вам клонировать ваш ev.target с помощью метода Node.cloneNode() и добавитьклон к ev.target.parentElement с использованием Node.insertBefore(). MDN в .insertBefore ()

0 голосов
/ 18 декабря 2018

Используя jquery и jquery UI, я сделал нечто подобное некоторое время назад.Я не создавал функцию «сделать новую карту», ​​я начал с «панели запуска» и создал две области, в которые можно добавлять и переключать карты - подобно тому, что у вас есть.Использование «пересечения», насколько я помню, стало переломным моментом для того, чтобы заставить его работать так, как я хотел - возможность перемещать элементы вверх и вниз по списку (поэтому они не обязательно возвращаются туда, откуда они возникли).Возможно, это может быть отправной точкой для вас?Вот скрипка (jquery старый .. рекомендуем обновить до более новых версий)

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Я сделал несколько небольших изменений в вашем коде, чтобы добавить контур и изменить курсор при движении.Согласно комментарию к другому вопросу , добавление границы является наиболее эффективным способом создания визуального эффекта «контура».Существует более длинный способ создания «сортируемого» эффекта, который демонстрируется в этом коде , который я обнаружил и объяснил просто, функция основана на вычислении положения при наведении и если перетаскиваемый элемент находится на полпути надэлемент в списке, эффект отображается, и элемент можно поместить между элементами списка.

Надеюсь, это достаточно ясно!

// Tells the other side what data is being passed (e.g. the ID is targeted)
var dropTarget = document.querySelector(".drop-target");
var draggables = document.querySelectorAll(".drag-task");

// Tells the other side what data is being passed (e.g. the ID is targeted)
draggables.forEach(item => {
  item.addEventListener("dragstart", function(ev) {
    ev.dataTransfer.setData("srcId", ev.target.id);
  });
})
// The end destination, prevent browsers default drag and drop (disabling breaks feature)
// because it's disabled by browsers by default
dropTarget.addEventListener('dragover', function(ev) {
  ev.preventDefault();
});
// End destination where item is dropped into
dropTarget.addEventListener('drop', function(ev) {
  ev.preventDefault();
  let target = ev.target;
  let droppable = target.classList.contains('drag-box');
  let srcId = ev.dataTransfer.getData("srcId");

  if (droppable) {
    ev.target.appendChild(document.getElementById(srcId));
  }
});
.drag-box {
  background-color: lightgray;
  float: left;
  width: 120px;
  min-height: 80px; /*lengthened the height slightly*/
  padding-bottom: 30px;
  height: auto;
  margin: 30px;
  cursor: move; /*added the 'cross' cursor*/
}
.drag-task {
  background-color: white;
  margin: 10px;
  padding: 5px; /*added padding to make tiles bigger*/
  border:1px dashed #000000; /*set an outline*/
}

.drop-active {
  border: 1px dashed red;
  cursor: pointer; /*change the pointer back to the default cursor while moving between lists*/
}
<div class="drop-target">
  <div class="drag-box">
    <div class="drag-card">
      <div draggable="true" id="task1" class="drag-task">Test Card 1</div>
    </div>
    <div class="drag-card">
      <div draggable="true" id="task2" class="drag-task">Test Card 2</div>
    </div>
    <div class="drag-card">
      <div draggable="true" id="task3" class="drag-task">Test Card 3</div>
    </div>
  </div>
  
  <!-- added tiles to the 2nd list (and deleted 3rd box)-->
  <div class="drag-box">
    <div class="drag-card">
      <div draggable="true" id="orange" class="drag-task">Orange</div>
    </div>
    <div class="drag-card">
      <div draggable="true" id="apple" class="drag-task">Apple</div>
    </div>
    <div class="drag-card">
      <div draggable="true" id="pear" class="drag-task">Pear</div>
    </div>
  </div>

$("#launchPad").height($(window).height() - 20);
var dropSpace = $(window).width() - $("#launchPad").width();
$("#dropZone").width(dropSpace - 70);
$("#dropZone").height($("#launchPad").height());

$(".card").draggable({
    appendTo: "#launchPad",
    cursor: "move",
    helper: 'clone',
    revert: "invalid",

});

$("#launchPad").droppable({
    tolerance: "intersect",
    accept: ".card",
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    drop: function(event, ui) {
        $("#launchPad").append($(ui.draggable));
    }
});

$(".stackDrop").droppable({
    tolerance: "intersect",
    accept: ".card",
    activeClass: "ui-state-default",
    hoverClass: "ui-state-hover",
    drop: function(event, ui) {        
        $(this).append($(ui.draggable));
    }
});
body { 
    margin: 0;
    background-color: #ffffcc;
}
#launchPad {
    width:170px;
    float:left;
    border: 1px solid #eaeaea;
    background-color: #f5f5f5;
}
#dropZone {
    float:right;
    border: 1px solid #eaeaea;
    background-color: #ffffcc;
}
.card { 
    width: 130px; 
    padding: 5px 10px;
    margin:5px;
    border:1px solid #ccc;
    background-color: #eaeaea;
}
.stack {
  display:inline-block;
   vertical-align:top;
    width: 180px;
    border: 1px solid #ccc;
    background-color: #f5f5f5;
    margin: 20px;
}
.stackHdr {
    background-color: #eaeaea;
    border: 1px solid #fff;
    padding: 5px 
}
.stackDrop {
    min-height:100px;
    padding: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>

<div id="launchPad">    
    <div class="card draggable" >
        apple
    </div> 
    <div class="card draggable">
        orange
    </div> 
    <div class="card draggable">
        banana
    </div> 
    <div class="card draggable">
        car
    </div> 
    <div class="card draggable">
        bus
    </div> 
</div>

<div id="dropZone">
    <div class="stack">
        <div class="stackHdr">
            Drop here 
        </div>
        <div class="stackDrop droppable">
            
        </div>
    </div>
    
    <div class="stack">
        <div class="stackHdr">
            Or here
        </div>
        <div class="stackDrop droppable">
            
        </div>
    </div>
</div>
...