前端拖拽组件实践
前言
这几年做的可视化项目越来越多,这需要前端的 drag
和 drop
元素能力(下文简称 dnd
),dnd
能力极大提高前端交互能力。然而在开发项目期间很少去了解其运行原理,这段时间趁着空余时间算是系统学习下前端 dnd
事件能力吧。
上面讲述到的 drag
和 drop
是前端元素上的事件,除了监听这俩个事件之外,还需要对元素进行拖拽支持:
<style>
.drag {
position: relative;
width: 100px;
height: 100px;
color: #fff;
text-align: center;
line-height: 100px;
background: #ccc;
user-select: none;
cursor: grab;
}
.drop {
position: absolute;
top: 0;
left: 200px;
width: 400px;
height: 400px;
background: #eee;
}
</style>
<div class="app-wrapper">
<div class="drag-wrapper">
<div draggable="true" id="dragger" class="drag">
拖动元素
</div>
</div>
<div class="drop-wrapper">
<div class="drop">
放置区域
</div>
</div>
</div>
只需要在需要拖拽的元素上添加 draggable
属性,该属性的值是布尔值:
true
表示元素可以被拖动false
表示元素不可以被拖动
简单的拖拽例子就这样出来了,但还是远远不够,需要监听对应的事件来满足某些需求。
事件
dnd
事件主要分为拖拽和放置俩大事件类型。
拖拽事件如下:
dragstart
开始拖拽元素返回回调事件drag
拖拽期间一定频率返回回调事件dragend
拖拽结束返回回调事件
放置事件如下:
dragenter
当拖拽元素拖到可放置元素时候返回回调事件dragover
当拖拽元素拖到可放置元素期间一定频率返回回调事件dragleave
当拖拽元素离开可放置元素时候返回回调事件drop
当拖拽元素在放置元素放置返回回调事件
拖拽数据
上面列出都会有 DragEvent
回调事件,回调事件中有个 dataTransfer
属性,关于他的介绍如下:
DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据。它可以保存一项或多项数据,这些数据项可以是一种或者多种数据类型。
这个属性主要包含:
dropEffect
effectAllowed
files
包含数据传输中可用的所有本地文件的列表。items
(只读)types
(只读)
dropEffect
属性拖放操作的视觉效果:
none
copy
link
move
effectAllowed
用来指定当元素被拖放式所允许的视觉效果:
none
move
copy
link
copyMove
copyLink
linkMove
all
element.addEventListener('dragenter', event => {
event.dataTrasfer.dropEffect = 'move'
})
下面的例子可以利用 dataTransfer
属性将拖拽的元素在放置元素上起到放置效果作用:
<style>
body {
background-color: #F1C40F;
font-family: "Courier New";
}
.container {
display: grid;
grid-template-columns: 33% 33% 33%;
}
.draggable, .droptarget {
border: 20px solid white;
margin: 30px;
padding: 30px;
text-align: center;
color: white;
font-size: 2rem;
}
.one {
background-color: #f15e0f;
}
.two {
background-color: #a532f1;
}
.three {
background-color: #2274a5;
}
.droptarget {
border: 10px dashed white;
transition: border-width 0.5s linear;
}
.hover {
border-width: 20px;
}
</style>
<div class="container">
<div class="draggable one" draggable="true">
drag me
</div>
<div class="draggable two" draggable="true">
drag me
</div>
<div class="draggable three" draggable="true">
drag me
</div>
<div class="droptarget">drop here</div>
<div class="droptarget">drop here</div>
<div class="droptarget">drop here</div>
</div>
document.querySelectorAll('.draggable').forEach(item => {
item.addEventListener('dragstart', event => {
event.dataTransfer.setData('text/plain', getComputedStyle(item).backgroundColor)
})
})
document.querySelectorAll('.droptarget').forEach(item => {
item.addEventListener('dragover', event => {
event.preventDefault()
})
item.addEventListener('dragleave', event => {
item.classList.remove('hover')
})
item.addEventListener('dragenter', event => {
item.classList.add('hover')
})
item.addEventListener('drop', event => {
item.style.backgroundColor = event.dataTransfer.getData('text/plain')
})
})
利用 setData
方法设置对拖拽元素写入特定的信息,然后在放置元素读取信息来展示不同的效果。
结语
静下心来过一下其实这些东西也没那么复杂,看完之后对那些 dnd
轮子项目也差不多了解其中的架构吧。
参考资料: