javascript - 类似于 Trello 的 Javascript 拖放悬停临时 Div 占位符?
问题描述
我有一个基本的拖放式 trello 式看板。您可以在不同的灰色框之间拖动任务。它使用在这里找到的 HTML 拖放 API 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>
我想要实现的是与此处找到的此 gif 类似的效果。这会在拖动悬停效果上创建与类<div>
相同级别的另一个元素drag-card
,并相应地重新定位自身。
我知道我必须使用事件侦听器,但仅此而已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
项目来源的元素
解决方案
使用 jquery 和 jquery UI,我不久前做了类似的事情。我没有创建“制作新卡”功能,而是从“启动板”开始并创建了两个可放置的区域,可以将卡附加到这些区域并在它们之间切换 - 类似于您所拥有的。我记得使用“相交”是让它按我想要的方式工作的一个转折点——能够在列表中上下移动元素(因此它们不一定会移回它们的起源位置)。也许它可以成为您的起点?这是小提琴(jquery是旧的..建议更新到新版本)
希望这可以帮助。
编辑:我对您的代码进行了一些小调整,以添加轮廓并在移动时更改光标。根据对另一个问题的评论,添加边框是创建视觉“轮廓”效果的最有效方法。有一种更长的方法可以创建“可排序”效果,该效果在我发现的这个codepen中进行了演示,并简单解释,该功能基于计算悬停位置,如果拖动的元素位于列表中某个项目的一半,则效果显示,项目可以放在列表项目之间。
希望这足够清楚!
// 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>
推荐阅读
- reactjs - ReactJS 通过 cdn 导入模块
- visual-c++ - 从 Modbus 静态库继承基类会导致返回时堆栈指针无效,但直接使用基类时工作正常
- ios - 为什么在视图控制器被取消初始化并导致 SIGABRT 或 EXC_BAD_ACCESS 后观察者仍然活着?
- sql - 两个查询及其总和的差异
- machine-learning - 如何在 pytorch 基本示例中包含批量大小?
- apache-kafka - 首次启动的 Kafka 服务器和领导者故障阻塞消费者
- python - 在 Scikit-learn 的 LDA 实现中,“困惑度”(或“分数”)应该上升还是下降?
- macos - QtMac::toNSImage 架构 x86_64 的未定义符号
- php - MySQL 查询将相似视图汇总为一个结果视图
- javascript - 手风琴 - 打开另一项时关闭一项