Open zhangxinxu opened 4 years ago
#draggable {
width: 200px;
height: 20px;
text-align: center;
background: white;
}
#dropzone {
position: absolute;
top: 300px;
width: 200px;
height: 20px;
background: blueviolet;
margin-bottom: 10px;
padding: 10px;
}
.abs {
position: absolute;
z-index: 1;
}
<div id="draggable">
被拖拽的元素
</div>
<div id="dropzone"></div>
var draggable = document.querySelector('#draggable')
var dropzone = document.querySelector('#dropzone')
var { width, height } = draggable.getBoundingClientRect()
var hasTouch = false
draggable.addEventListener('touchstart', touchstart)
document.addEventListener('touchmove', touchmove)
draggable.addEventListener('touchend', touchend)
draggable.addEventListener('touchcancel', reset)
function touchstart() {
hasTouch = true
draggable.classList.add('abs')
}
function touchmove(e) {
if (hasTouch) {
var touch = e.changedTouches[0]
var pageX = touch.pageX
var pageY = touch.pageY
Object.assign(draggable.style, {
left: pageX - width / 2 + 'px',
top: pageY - height / 2 + 'px'
})
}
}
function touchend(e) {
hasTouch = false
var touch = e.changedTouches[0]
var pageX = touch.pageX
var pageY = touch.pageY
var elements = document.elementsFromPoint(pageX, pageY)
if (elements.includes(dropzone)) {
dropzone.appendChild(draggable)
draggable.removeEventListener('touchstart', touchstart)
document.removeEventListener('touchmove', touchmove)
draggable.removeEventListener('touchend', touchend)
draggable.removeEventListener('touchcancel', reset)
}
reset()
}
function reset() {
draggable.classList.remove('abs')
Object.assign(draggable.style, {
left: '',
top: ''
})
}
移动端可以使用touchEvent来处理拖拽操作;
<div id="t1">A</div>
<div id="t2">B</div>
body {
max-width: 400px;
}
#t1 {
width: 100px;
height: 100px;
background-color: lightcoral;
}
#t2 {
min-height: 200px;
margin-top: 30px;
background-color: lightcyan;
}
const A = document.getElementById('t1')
const B = document.getElementById('t2')
let first = null
function start (e) {
first = e.touches[0]
}
function move (e) {
const cur = e.touches[0]
if (first) {
A.style.transform = `translate(${cur.pageX - first.pageX}px, ${cur.pageY - first.pageY}px)`
}
}
function end (e) {
const boxA = A.getBoundingClientRect()
const boxB = B.getBoundingClientRect()
if ( boxA.left > boxB.left
&& boxA.top > boxB.top
&& boxA.right < boxB.right
&& boxA.bottom < boxB.bottom ) { // 判断拖放停止的位置是否完全处于B之中
A.removeEventListener('touchstart', start)
A.removeEventListener('touchmove', move)
A.removeEventListener('touchend', end)
B.appendChild(A)
}
A.style.transform = 'none'
}
A.addEventListener('touchstart', start)
A.addEventListener('touchmove', move)
A.addEventListener('touchend', end)
在线DEMO: jsbin
并没有实现 移动中的效果,只判断结束时候的状态
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> <style> .ele{ min-height: 100px; background-color:rgba(255,0,0,0.4); padding:8px; } </style> </head> <body> <div draggable="true" class="ele" id="eleA"></div> <hr> <div class="ele" id="eleB"></div> </body> </html>
var eleA = document.getElementById("eleA"); var eleB = document.getElementById("eleB"); document.addEventListener("touchend", function (e) { // 移动的是 A 元素,并且A 元素不在B元素之内 if (e.target === eleA && !eleB.contains(eleA)) { var objTouch = e.changedTouches[0]; var rect = eleB.getBoundingClientRect(); var xIn = objTouch.clientX < rect.right && objTouch.clientX > rect.left; var yIn = objTouch.clientY < rect.bottom && objTouch.clientY > rect.top; xIn && yIn && eleB.appendChild(eleA); } });
<div class="a"> </div>
<div class="b"></div>
let inDrag = false, timer = null, touchpos = { x: 0, y: 0 }
const a = document.querySelector('.a'), b = document.querySelector('.b')
b.addEventListener('touchstart', (e) => {
const { pageX, pageY } = e.changedTouches[0];
timer = setTimeout(() => {
inDrag = true
touchpos.x = pageX
touchpos.y = pageY
b.style.opacity = '.5'
}, 50)
})
b.addEventListener('touchend', (e) => {
if (!inDrag) {
return
}
// 防止 elementFromPoint 拿到b
b.style.display = 'none'
clearTimeout(timer)
const { pageX, pageY } = e.changedTouches[0];
let isIna = false,
element = document.elementFromPoint(pageX, pageY);
while (element && element.parentElement) {
if (element.classList.contains('a')) {
isIna = true
break
}
element = element.parentElement
}
if (isIna) {
a.appendChild(b)
} else {
document.body.appendChild(b)
}
inDrag = false
// 还原
b.style.display = ''
b.style.transform = ''
b.style.opacity = ''
})
b.addEventListener('touchmove', (e) => {
if (!inDrag) {
return
}
e.preventDefault()
e.stopPropagation()
const { pageX, pageY } = e.changedTouches[0]
b.style.transform = `translate(${-touchpos.x + pageX}px,${-touchpos.y + pageY}px)`
})
div {
background-color: rgba(0,0,0,0.08);
border: 1px solid
}
#dragable {
height: 100px;
width: 100px;
}
#container {
height: 200px;
width: 200px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="dragable">可拖动</div>
<div id="container"></div>
</body>
</html>
let dragable = document.getElementById('dragable'),
container = document.getElementById('container')
// console.log(dragable, container)
dragable.addEventListener('touchend', (e) => {
let b = container.getBoundingClientRect()
// console.log(a, b)
// console.log(e.touches, e.changedTouches, e.targetTouches)
let touches = e.changedTouches[0]
console.log(e.changedTouches)
if(
touches.clientX > b.left &&
touches.clientX < b.right &&
touches.clientY > b.top &&
touches.clientY < b.bottom
) {
container.appendChild(dragable)
}
})
移动端,页面上A,B两个div元素,请实现:
拖拽A元素到B元素上,A元素append到B元素中。
本题考点在于移动端的拖拽功能实现。大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。
其他 本期小测没有直播,也没有打分,但是会反馈要点。