最近作到的react項目就有一個拖拽的需求,而後大概搜索了一下,找到了star比較高的
react-dnd
庫,可是閱讀react-dnd
的官方文檔仍是有點難受的
,由於概念性比較強
,因此在介紹react-dnd
以前咱們來實現原生拖拽
javascript
在h5以前,原生實現拖拽是根據
Mouse事件來實現的
,須要用到如下這三個事件mousedown
,mouseup
,mousemove
css
明白了上述👆三個事件方法的做用以及
JavaScript三你們族
,咱們來實現個簡單版的拖拽html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img id="ball" src="https://js.cx/clipart/ball.svg" alt="">
<script>
const ball=document.querySelector("#ball")
ball.onmousedown = function(event) {
let shiftX = event.clientX - ball.getBoundingClientRect().left;
let shiftY = event.clientY - ball.getBoundingClientRect().top;
ball.style.position = 'absolute';
ball.style.zIndex = 1000;
document.body.append(ball);
moveAt(event.pageX, event.pageY);
// 移動如今位於座標 (pageX, pageY) 上的球
// 將初始的偏移考慮在內
function moveAt(pageX, pageY) {
ball.style.left = pageX - shiftX + 'px';
ball.style.top = pageY - shiftY + 'px';
}
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
// 在 mousemove 事件上移動球
document.addEventListener('mousemove', onMouseMove);
// 放下球,並移除不須要的處理程序
ball.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
ball.onmouseup = null;
};
};
ball.ondragstart = function() {
return false;
};
</script>
</body>
</html>
複製代碼
效果以下:html5
ball.ondragstart = function() {
return false;
};
複製代碼
若是不設置這段代碼,會發生奇怪的現象,這是由於瀏覽器有本身的對圖片和一些其餘元素的拖放處理
,會在咱們拖放時自動運行,這與咱們的拖放處理產生了衝突。java
HTML 的 drag & drop 使用了
DOM event model
以及從mouse events
繼承而
來的drag events
。一個典型的drag
操做是這樣開始的:用戶用鼠標選中一個可拖動的(draggable)元素,移動鼠標到一個可放置的(droppable)元素,而後釋放鼠標。 在操做期間,會觸發一些事件類型,有一些事件類型可能會被屢次觸發(好比drag 和 dragover 事件類型)react
注意理解上述👆的概念有注意理解
react-dnd
庫的apiweb
舉個例子🌰:api
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
body {
font: 16px Arial, Helvetica, sans-serif;
}
li {
width:200px;
height: 40px;
text-align: center;
line-height: 40px;
border:1px dashed #cccccc;
cursor: pointer;
user-select: none;
background-color: white;
list-style: none;
}
.more {
border-top: 1px dotted rgb(196, 196, 196);
font-size: 12px;
padding-top: 10px;
}
.more,
.more a {
color: rgb(96, 96, 96);
}
</style>
</head>
<body>
<ul>
<li
draggable="true"
ondragend="dragEnd()"
ondragover="dragOver(event)"
ondragstart="dragStart(event)"
>
Apples
</li>
<li
draggable="true"
ondragend="dragEnd()"
ondragover="dragOver(event)"
ondragstart="dragStart(event)"
>
Oranges
</li>
<li
draggable="true"
ondragend="dragEnd()"
ondragover="dragOver(event)"
ondragstart="dragStart(event)"
>
Bananas
</li>
<li
draggable="true"
ondragend="dragEnd()"
ondragover="dragOver(event)"
ondragstart="dragStart(event)"
>
Strawberries
</li>
</ul>
<script>
var selected;
const li = document.createElement("li");
function dragOver(e) {
// 向前拖拽 向後拖拽
// 拖動目標(drop)是否是在拖拽源(drag)的前面
if (isBefore(selected, e.target)){
e.target.parentNode.insertBefore(selected, e.target);
}else {e.target.parentNode.insertBefore(selected, e.target.nextSibling);}
}
function dragEnd() {
selected = null;
}
function dragStart(e) {
selected = e.target;
console.log(selected)
}
function isBefore(el1, el2) {
var cur;
if (el2.parentNode === el1.parentNode) {
for (cur = el1.previousSibling; cur; cur = cur.previousSibling) {
if (cur === el2) return true;
}
} else return false;
}
</script>
</body>
</html>
複製代碼
效果圖:瀏覽器
是否是很接近咱們的
需求啦
app
拖動過程當中,
瀏覽器會在鼠標旁顯示一張默認圖片
。固然,應用程序也能夠經過setDragImage() 方法
自定義一張圖片,以下面的例子所示。
function dragStart(e) {
selected = e.target;
dragstart_handler(e)
// 延時是爲了瀏覽器能生成拖拽圖片
setTimeout(()=>{
selected.style.opacity='0'
},0)
}
function dragstart_handler(ev) {
var img = new Image();
img.src = 'https://js.cx/clipart/ball.svg';
ev.dataTransfer.setDragImage(img, 10, 10);
}
複製代碼
dropEffect
屬性用來控制拖放操做中用戶給予的反饋。它會影響到拖動過程當中瀏覽器顯示的鼠標樣式。好比,當用戶懸停在目標元素上的時候,瀏覽器鼠標也許要反映拖放操做的類型。
有 3 個效果能夠定義: