拖放是很常見的一種交互效果,很多時候我們都會藉助於第三方的控件來實現,其實用原生js實現起來也非常的方便。接下來我們就用原生js和css快速實現這樣的拖放效果:
HTML
HTML的內容很簡單,就是五個空的容器和一個可以被拖拽的元素:
html:
<body>
<div class="droppable">
<div class="draggable" draggable="true"></div>
</div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
</body>
注意點:1. 容器的的class
爲droppable
,用於接收被拖拽的元素,可被拖拽的元素class
爲draggable
,同時設置draggable
屬性爲true
,表示該元素可以被拖拽。2. 默認情況下,只有圖片、鏈接還有被選中的文字能被拖拽,其他元素需要設置draggable
爲true
才能被拖拽。所以爲了凸顯draggable
的用法,這裏使用<div>
而不是<image>
來作爲被拖拽的元素。
CSS
在實現樣式的時候,除了實現靜態的樣式,一些過渡狀態也需要增加樣式以提升視覺體驗:1. 元素被拖動的過程中增加邊框等效果;2. 當元素被拖動到容器上方時,容器也應增加樣式表明容器可以接收一個被拖拽的元素。
css:
body {
background-color: darksalmon;
}
.draggable {
background-image: url('http://source.unsplash.com/random/150x150');
position: relative;
height: 150px;
width: 150px;
top: 5px;
left: 5px;
cursor: pointer;
}
.droppable {
display: inline-block;
height: 160px;
width: 160px;
margin: 10px;
border: 3px salmon solid;
background-color: white;
}
.dragging {
border: 4px yellow solid;
}
.drag-over {
background-color: #f4f4f4;
border-style: dashed;
}
.invisible {
display: none;
}
注意點:1. 圖片來源於https://source.unsplash.com/
的隨機圖片;2..dragging
爲draggable元素正在被拖動的狀態,增加黃色border;3..drag-over
爲draggable元素被拖動到容器上方時容器的狀態,增加灰色虛線border。
JS
最後,我們需要通過js監聽draggable
和droppable
的相關的事件。
js:
// 查詢draggable和droppable
const draggable = document.querySelector('.draggable');
const droppables = document.querySelectorAll('.droppable');
// 監聽draggable的相關事件
draggable.addEventListener('dragstart', dragStart);
draggable.addEventListener('dragend', dragEnd);
function dragStart() {
this.className += ' dragging';
setTimeout(() => {
this.className = 'invisible';
}, 0);
}
function dragEnd() {
this.className = 'draggable';
}
// 監聽droppable的相關事件
for (const droppable of droppables) {
droppable.addEventListener('dragover', dragOver);
droppable.addEventListener('dragleave', dragLeave);
droppable.addEventListener('dragenter', dragEnter);
droppable.addEventListener('drop', dragDrop);
}
function dragOver(e) {
e.preventDefault();
}
function dragEnter(e) {
e.preventDefault();
this.className += ' drag-over';
}
function dragLeave(e) {
this.className = 'droppable';
}
function dragDrop(e) {
this.className = 'droppable';
this.append(draggable);
}
注意點:1. 當draggable元素被拖動時,原來容器中的draggable元素並不會消失,需要我們手動將其隱藏(class
設置爲invisible
),如果同步操作會立馬觸發dragend
事件導致拖動效果消失,所以在setTimeout
的回調中異步設置可確保拖動操作開始後再隱藏draggable元素;2. 在dragEnter
和dragOver
方法中我們需要通過preventDefault
來取消事件以表明容器是一個合法的droppable
元素,不然容器的drop
事件將無法觸發,接下來的操作也將無法進行,詳細解釋請參考 MDN DropTarget;3. 在dragDrop
方法中直接使用append
方法將draggable
元素移動至當前容器下面。
好了,demo比較簡單,但是細節還是有一些的,自己實踐一下才能更深刻的領悟。