题目
页面内有一个正方形元素 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))
})