拖拽
HTML5 的拖放 API 能够支持在网站内部和网站之间拖放项目。同时也提供了一个更简单的供扩展和基于 Mozilla 的应用程序使用的 API。一个典型的drag操作是这样开始的:
- 用户用鼠标选中一个可拖动的(draggable)元素
- 移动鼠标到一个可放置的(droppable)元素
- 然后释放鼠标。
相关事件
- 源对象:
- dragstart:源对象开始拖放。
- drag:源对象拖放过程中。
- dragend:源对象拖放结束。
- 过程对象:
- dragenter:源对象开始进入过程对象范围内。
- dragover:源对象在过程对象范围内移动。
- dragleave:源对象离开过程对象的范围。
- 目标对象:
- drop:源对象被拖放到目标对象内。
draggable 属性
想要拖放某个元素,必须设置该元素的 draggable 属性为 true,当该属性为 false 时,将不允许拖放。而 img 元素和 a 元素都默认设置了 draggable 属性为 true,可直接拖放,如果不想拖放这两个元素,把属性设为 false 即可。
<div class="item" draggable="true">可以拖拽元素</div>
dataTransfer 对象
在所有拖放事件中提供了一个数据传递对象 dataTransfer,用于在源对象和目标对象间传递数据。接下来认识一下这个对象的方法和属性,来了解它是如何传递数据的。dataTransfer 对象不支持IE,所以尽量用别的方法来存储我们需要的信息。以下简短介绍下其方法:
- setData()
- getData()
- clearData()
- setDragImage()
- effectAllowed 和 dropEffect 属性
放置区域
当拖动一个项目到HTML元素中时,浏览器默认不会有任何响应。想要让一个元素变成可释放区域,该元素必须设置ondragover和ondrop事件处理程序属性。注意每个处理程序调用preventDefault()来阻止对这个事件的其它处理过程(如触点事件或指针事件)。下面的例子通过简单的事件处理展示了如何使用这些属性:
<p id="p1" draggable="true" ondragstart="dragstart_handler(event);">This element is draggable.</p>
<div id="target" ondrop="drop_handler(event);" ondragover="dragover_handler(event);">Drop Zone</div>
function dragstart_handler(ev) {
// Add the target element's id to the data transfer object
ev.dataTransfer.setData("text/plain", ev.target.id);
ev.dropEffect = "move";
}
function dragover_handler(ev) {
ev.preventDefault();
// Set the dropEffect to move
ev.dataTransfer.dropEffect = "move"
}
function drop_handler(ev) {
ev.preventDefault();
// Get the id of the target and add the moved element to the target's DOM
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
拖放排序
<div class="container">
<div class="doing-section">
<p class="sub-title">进行中</p>
<div class="list">
<div class="item" draggable="true" data-id="1">1</div>
<div class="item" draggable="true" data-id="2">2</div>
<div class="item" draggable="true" data-id="3">3</div>
</div>
</div>
<div class="done-section">
<p class="sub-title">已完成</p>
<div class="list">
<div class="item" draggable="true" data-id="4">4</div>
<div class="item" draggable="true" data-id="5">5</div>
<div class="item" draggable="true" data-id="6">6</div>
</div>
</div>
<div class="delete-section">
<p class="sub-title">回收站</p>
</div>
</div>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,body{
height: 100%;
}
.container{
height: 100%;
display: flex;
padding: 10px;
}
.doing-section,.done-section,.delete-section{
display: flex;
flex-direction: column;
width: 288px;
margin-right: 10px;
background-color: #eee;
border-radius: 3px;
padding: 10px;
}
.sub-title{
padding: 14px 18px;
font-size: 15px;
font-weight: 700;
}
.list{
flex: auto;
}
.item{
background: #fff;
border-radius: 8px;
margin-bottom: 10px;
padding: 12px 10px 12px 20px;
line-height: 20px;
overflow: hidden;
}
.item:hover{
transition: all .2s ease;
border-left: 10px solid #ddd;
cursor: pointer;
}
.item.draging{
background: #f5f5f5;
opacity: .5;
}
var draging_id = null;
var draging_el = null;
var draging_pr = null;
// 开始选项拖拽
$('.item').on('dragstart',function(e){
let id = e.currentTarget.dataset.id;
$(this).addClass('draging');
draging_id = id;
draging_el = this;
draging_pr = this.parentNode;
console.log(id,'start');
e.originalEvent.dataTransfer.setData("text/plain",id);
e.originalEvent.dropEffect = "move";
})
// 拖拽结束
$('.item').on('dragend',function(e){
e.preventDefault();
let id = e.currentTarget.dataset.id;
$(this).removeClass('draging');
draging_id = null;
draging_el = null;
draging_pr = null;
console.log(id,'end')
})
// 拖拽排序
$('.item').on('dragenter',function(e){
e.preventDefault();
// 防止页面及页面以外的元素拖入报错
if(!draging_id || !draging_el || !draging_pr){
return
}
// 获取当前被覆盖元素的id
let id = e.currentTarget.dataset.id;
if(id !== draging_id ){
this.parentNode.insertBefore(draging_el,this);
}
})
// 拖拽排序底部位置
$('.list').on('dragover',function(e){
e.preventDefault();
// 防止页面及页面以外的元素拖入报错
if(!draging_id || !draging_el || !draging_pr){
return
}
var len = $(this).find('.item').length;
if(!len){
// 如果没有元素的话,直接添加过去
$(this).append(draging_el)
}else{
// 如何当前元素是最后一个元素,返回,不作处理
var lastchild = $(this).find('.item').eq(len - 1);
var lastchildId = lastchild.data('id');
if(lastchildId == draging_id){
return
}
// 如果鼠标位置高度大于最后一个元素高度的话,元素放在最后一个位置
var lastchildHeight = lastchild.innerHeight();
var lastchildTop = lastchild.offset().top;
var positionTop = lastchildTop + lastchildHeight;
var mouseTop = e.clientY;
if(mouseTop > positionTop){
$(this).append(draging_el)
}
}
})
// 回收站
$('.delete-section').on('dragover',function(e){
e.preventDefault();
}).on('drop',function(e){
// 防止页面及页面以外的元素拖入报错
if(!draging_id || !draging_el || !draging_pr){
return
}
e.preventDefault();
draging_pr.removeChild(draging_el);
})