使用js鼠标(mouse)事件实现拖放html元素
2021-08-09 本文已影响0人
mudssky
还是一个用react编写的toc组件的例子
我们把toc组件设置成fix定位,然后改变元素的style的left和top值,就能再页面上随意移动元素了.
为什么不用drag事件?
drag事件是html5新添加的api,所以它的兼容性会更差一些.
另外drag事件也不是很好用, 和我现在想要实现的功能差挺多的,而且复杂度反而更高.
下面是drag相关的6个事件,
drag是包含两个物体,从一个元素拖动进入另一个元素,
针对对象 | 事件名称 | 说明 |
---|---|---|
被拖动的元素 | dragstart | 在元素开始被拖动时候触发 |
drag | 在元素被拖动时反复触发 | |
dragend | 在拖动操作完成时触发 | |
目的地对象 | dragenter | 当被拖动元素进入目的地元素所占据的屏幕空间时触发 |
dragover | 当被拖动元素在目的地元素内时触发 | |
dragleave | 当被拖动元素没有放下就离开目的地元素时触发 |
而我目前的需求,只会使用到被拖动的元素本身.
所以并不适合用drag的api.
使用mouse 鼠标事件实现拖放
mouse事件相比drag更加底层,能实现更精细的控制.
下面是这个react组件,拖放事件的代码.
其中需要注意的是,
下面这行代码是必要的,因为浏览器自己的拖放处理和我们的拖放处理会产生冲突,我们用return false可以禁止默认行为.
tocEl.current.ondragstart = function () {
return false
}
// 添加拖拽组件位置的监听
useEffect(() => {
// 组件生成时,从localStorage获取过去使用的位置
const jsonstr = localStorage.getItem('tocposition')
let startPostion = { left: 20, top: 50 }
if (jsonstr) {
startPostion = JSON.parse(jsonstr)
}
let tocPosition = startPostion
function moveAt(tocPosition: { left: number; top: number }) {
tocEl.current!.style.left = tocPosition.left + 'px'
tocEl.current!.style.top = tocPosition.top + 'px'
}
moveAt(tocPosition)
if (tocEl.current) {
// console.log(tocEl)
const onMouseDown = function (event: MouseEvent) {
// 按下鼠标时,我们可以记住鼠标按下的位置相对于拖动地节点左上角的距离
const shiftX =
event.clientX - (tocEl.current?.getBoundingClientRect().left || 0)
const shiftY =
event.clientY - (tocEl.current?.getBoundingClientRect().top || 0)
// 按下鼠标后,添加移动事件和鼠标放下的事件
function onMouseMove(event: MouseEvent) {
// console.log(event.pageX, event.pageY, event.clientX, event.clientY)
tocPosition = {
left: event.clientX - shiftX,
top: event.clientY - shiftY,
}
moveAt(tocPosition)
}
document.addEventListener('mousemove', onMouseMove)
function onMouseUp(event: MouseEvent) {
// 放下后移除事件
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
localStorage.setItem('tocposition', JSON.stringify(tocPosition))
}
document.addEventListener('mouseup', onMouseUp)
}
tocEl.current.addEventListener('mousedown', onMouseDown)
tocEl.current.ondragstart = function () {
return false
}
}
return () => {
// cleanup
}
}, [])