思路整理
要实现拖拽,顾名思义,就是鼠标移动时dom跟着移动;
那就要拿到鼠标的点击(mousedown)移动(mousemove)和抬起(mouseup)的动作,并在这三个动作上面增加一些操作逻辑;
点击(mousedown):获取鼠标当前的位置以及目标dom的位置,得到这两个的初始移动值;
移动(mousemove):鼠标移动时,获取当前的位置得到鼠标移动的差值,也是目标dom的移动距离;即:
鼠标移动后的位置 – 鼠标开始的位置 = 目标dom移动后的位置 – 目标dom初始的位置
所以计算出鼠标移动后的差值,减去目标dom的值就等于目标dom移动后的位置;
代码实现
既然要移动,那我们不得不使用translate平移,如果要使用此属性的话,需要验证浏览器支持哪种transform的写法;
// 获取transform兼容的写法
const getTransform = () => {
let transform = '';
const divStyle = document.createElement('div').style,
_transforms = ['transform', 'webkitTransform', 'MozTransform', 'msTansform',
'OTransform'],
len = _transforms.length;
for(let i = 0; i < len; i++) {
if(_transforms[i] in divStyle) {
return transform = _transforms[i]
}
}
return transform
}
复制代码
如果浏览器不支持的话,就用定位left/top去移动,这次就不考虑这个了;
考虑有些小伙伴还在用IE,虽然马上退市了(偷笑),但是还是做了兼容;
// currentStyle是IE中获取style的属性
const getStyle = (elem, property) => {
return window.getComputedStyle ? window.getComputedStyle(elem, false)[property] :
elem.currentStyle[property]
}
复制代码
有了上面两个方法,接下来就可以开始正式的代码了
首先设置默认的元素值
let startX = 0 鼠标开始的位置
let startY = 0 鼠标结束的位置
let isDrop = false 获取是否开始移动
let sourceX = 0 目标开始的位置
let sourceY = 0 目标结束的位置
// 获取元素的初始位置
const getTargetPos = elem => {
let pos = { x: 10, y: 0 }
const transform = getTransform()
if(transform) {
const transformValue = getStyle(elem, transform)
if(transformValue === 'none') {
elem.style[transform] = 'translate(0, 0)'
return pos
} else {
const temp = transformValue.match(/-?\d+/g)
return pos = {
x: parseInt(temp[4].trim()),
y: parseInt(temp[5].trim()),
}
}
} else {
if(getStyle(elem, 'position') == 'static') {
elem.style.position = 'relative'
return pos
} else {
const x = parseInt(getStyle(elem, 'left') ? getStyle(elem, 'left') : 0)
const y = parseInt(getStyle(elem, 'top') ? getStyle(elem, 'top') : 0)
return pos = {
x: x,
y: y
}
}
}
}
复制代码
设置元素的位置
const setTargetPos = (elem, pos) => {
const transform = getTransform()
if(transform) {
elem.style[transform] = 'translate('+pos.x + 'px, '+ pos.y +'px)'
} else {
elem.style.left = pos.x + 'px'
elem.style.top = pos.y + 'px'
}
return elem
}
复制代码
鼠标点击时
const start = event => {
console.log('start')
const autumn = document.querySelector('.autumn')
startX = event.pageX
startY = event.pageY
const pos = getTargetPos(autumn)
sourceX = pos.x
sourceY = pos.y
isDrop = true
}
复制代码
鼠标移动时
const move = event => {
console.log('move')
if (isDrop) {
const autumn = document.querySelector('.autumn')
const currentX = event.pageX
const currentY = event.pageY
const distanceX = currentX - startX
const distanceY = currentY - startY
setTargetPos(autumn, {
x: (sourceX + distanceX).toFixed(),
y: (sourceY + distanceY).toFixed(),
})
} else {
return
}
}
复制代码
鼠标抬起结束时
const end = () => {
document.removeEventListener('mousemove', move)
document.removeEventListener('mouseup', end)
isDrop = false
//可以写自己的任务代码的逻辑
}
复制代码
本次用的hooks
useEffect(() => {
const autumn = document.querySelector('.autumn')
autumn.addEventListener('mousedown', start, false)
document.onmousemove = move
autumn.addEventListener('mouseup', end, false)
}, [])
复制代码
页面元素
return (
<div className="autumn"
style={{ width: '30px', height: '20px', backgroundColor: 'pink' }}
>
{props.button()}
</div>
)
复制代码
为了不写样式文件,此次都写的行内,不喜勿喷哦
文章借鉴自: 《JavaScript核心技术开发解密》
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END