題目
頁面內有一個正方形元素 A 以及一個待放置區域 B,實現對其拖拽和放下到 B 區域內,並且改變 B 區域背景顏色 (不可用 html5 原生事件)。
這也是一道騰訊面試題,要求遠程編程。
思路
用鼠標的mousedown事件來模擬dragstart
用持續的mousedown事件來模擬drag過程,用event的座標來改變相關element的座標
經試驗,H5原生是以被拖拽元素在容器元素中的面積達到一半時可以觸發drop(待確認),簡易版的就不算面積了,以鼠標進入容器中爲準,用mouseup事件作爲觸發條件模擬drop
代碼
html部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<link rel="stylesheet" type="text/css" href="demo.css" />
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script src="demo.js"></script>
</body>
</html>
css部分
#div1{
width:100px;
height: 100px;
margin:200px auto;
background: olive;
}
#div2{
width: 200px;
height: 300px;
position: absolute;
left:100px;
top:500px;
background: lightpink;
}
js部分
//var _origin = {x: div1.offsetLeft, y:div1.offsetTop}
var _newele = document.createElement('div')
var div1Style = getComputedStyle(div1)
var dropFlag = 0, dragFlag = 0
div1.addEventListener('mousedown', (event) => {
var _ele = event.target
_newele.style.width = div1Style.width
_newele.style.height = div1Style.height
_newele.style.backgroundColor = div1Style.backgroundColor
_newele.style.position = 'absolute'
_newele.style.left = _ele.offsetLeft + 'px'
_newele.style.top = _ele.offsetTop + 'px'
_newele.style.zIndex = 1
_ele.style.position = 'absolute'
_ele.style.left = _newele.style.left
_ele.style.top = _newele.style.top
_ele.style.margin = '0'
_ele.style.opacity = .5
_ele.style.zIndex = 2
document.body.append(_newele)
dragFlag = 1
})
div1.addEventListener('mouseup', (event) => {
dragFlag = 0
console.log(dropFlag)
// 恢復原樣,簡易版就直接幹掉div1,否則應該存儲所有的style值,幹掉new div,讓div1迴歸原位
if(!dropFlag){
document.body.removeChild(div1)
}
else{
console.log('now drop in div2')
div2.style.backgroundColor = '#ccc000'
}
})
div1.addEventListener('mousemove',(event) => {
if(!dragFlag) return false;
var _ele = event.target
_ele.style.left = event.clientX - parseInt(div1Style.width)/2 + 'px'
_ele.style.top = event.clientY - parseInt(div1Style.height)/2 + 'px'
if(isEnter({left: event.clientX, top: event.clientY}, div2)){
dropFlag = 1
div1.style.cursor = 'copy'
}
else{
dropFlag = 0
div1.style.cursor = 'move'
}
})
//mouseenter事件直到mouseup事件觸發後才觸發,不能用mouseenter了,只能用函數判斷鼠標座標是不是在div2元素的範圍內了
function isEnter( point = {left : 0 ,top : 0}, ele ){
var minLeft = ele.offsetLeft, maxLeft = ele.offsetLeft + ele.offsetWidth
var minTop = ele.offsetTop, maxTop = ele.offsetTop + ele.offsetHeight
if( point.left > minLeft && point.left < maxLeft && point.top > minTop && point.top < maxTop){
//console.log('enter', ele)
return true
}
return false
}
效果圖
忽略那個圓圈,,,那個是錄屏軟件的。
順帶吐個槽,screencastify 還需要load才能使用,不然安裝了也不行。最後用的是mac自帶的 quicktime
拖拽庫
常用的應該是jquery UI 吧。
還有專門的拖放庫dnd.js
HTML5的拖拽API
解決完畢,再來了解一下html5的原生api:HTML5魔法堂:全面理解Drag & Drop API - ^_^肥仔John - 博客園
html5的原生事件版本
div1.addEventListener('dragstart',(event) => {
//event.dataTransfer.setDragImage(img, 20, 20)
event.dataTransfer.setData('Text', event.target.id)
})
div2.addEventListener('dragenter',(e) => {
console.log('now enter the div2')
})
div2.addEventListener('dragover',(e) => {
e.dataTransfer.dropEffect = 'copy' //chrome 下默認就是copy, 也可以對鏈接用 link
e.preventDefault()
})
div2.addEventListener('drop', (e) => {
var _id = e.dataTransfer.getData('Text')
e.target.appendChild(document.getElementById(_id))
})