浏览器鼠标事件原生api实现拖拽性能
波及技术点
一、Mouse Api
1、mouseenter
:鼠标移入事件;当鼠标移入到指定元素上时触发;从子元素的移入不会触发该事件;不反对事件冒泡
2、mouseleave
:鼠标来到事件;当鼠标指针移出指定元素时就会触发;从以后元素移入到子元素不会触发该事件;不反对事件冒泡
3、mouseover
:鼠标移入事件;当鼠标移入到指定元素上时触发;从子元素的移入会触发该事件
4、mouseout
:鼠标来到事件;当鼠标指针移出指定元素时就会触发;从以后元素移入到子元素会触发该事件
5、mousedown
:鼠标按键按下时会触发该事件;在鼠标按键按下时会触发(左键、右键和滚轮按下后均会触发)
6、mouseup
:鼠标按键弹起事件;在鼠标按键抬起时会触发(左键、右键和滚轮抬起后均会触发)
7、mousemove
:鼠标挪动事件;鼠标在指定元素对象上挪动时就会触发
二、DOM元素数据
1、offsetTop、offsetLeft
:示意该元素的左上角与父容器(offsetParent对象)左上角的间隔。
2、clientWidth、clientHeight
:示意元素的内容局部再加上padding的所占据的视觉面积,不包含border和滚动条占用的空间。
3、offsetWidth、offsetHeight
:示意元素的内容局部再加上padding、border的所占据的视觉面积,不包含滚动条占用的空间。
案例实现
1.第一步:筹备DOM元素
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>浏览器鼠标事件原生api实现拖拽性能</title> <style type="text/css"> * { padding: 0; margin: 0; } body { box-sizing: border-box; padding: 50px; width: 100vw; height: 100vh; } #parent { box-sizing: border-box; position: relative; height: 300px; background: #ededed; } #dragItem { display: inline-block; padding: 10px 15px; background: #2f54eb; color: #fff; font-size: 14px; cursor: pointer; } </style></head><body> <!-- 父容器 --> <div id="parent"> <!-- 可拖拽子项 --> <div id="dragItem">我是可拖拽子项</div> </div></body></html>
2.第二步:初始化数据及增加监听事件
// 获取要增加监听事件的DOM元素var parent = document.getElementById("parent")var dragItem = document.getElementById("dragItem")// 申明过程中应用到的变量// dragingState:鼠标是否处于拖拽状态// fromX:鼠标开始拖拽时,记录鼠标的x地位// fromY:鼠标开始拖拽时,记录鼠标的y地位// fromOffsetTop:鼠标开始拖拽时,记录拖拽元素间隔父元素的顶部间隔// fromOffsetLeft:鼠标开始拖拽时,记录拖拽元素间隔父元素的左部间隔var dragingState,fromX,fromY,fromOffsetTop,fromOffsetLeft// 当页面加载实现,对相应DOM元素增加监听事件window.onload = function () { document.body.addEventListener('mousemove', listenMouseMove) parent.addEventListener('mouseenter', listenParentMouseEnter) parent.addEventListener('mouseleave', listenParentMouseLeave) dragItem.addEventListener('mousedown', listenMouseDown) dragItem.addEventListener('mouseup', listenMouseUp)}
3.第三步:增加监听鼠标挪动事件处理
// 监听鼠标挪动事件function listenMouseMove(e) { // 当鼠标不处于拖拽状态时,间接返回,不往下继续执行 if (!dragingState) return const { x, y } = e // 如果鼠标地位在父容器内部则触发开释资源 if (x < parent.offsetLeft || x > parent.offsetLeft + parent.offsetWidth || y < parent.offsetTop || y > parent.offsetTop + parent.offsetHeight) { // 创立一个鼠标mouseup事件 const eventObj = document.createEvent('MouseEvents') eventObj.initMouseEvent('mouseup') dragItem.dispatchEvent(eventObj) return } // 失常挪动 const moveX = x - fromX const moveY = y - fromY parent.style.border = '1px dashed #ccc' let changeX = fromOffsetLeft + moveX let changeY = fromOffsetTop + moveY // 当挪动间隔会让子元素位于父元素之外时,解决最大最小数据 if (changeX < 0) { changeX = 0 } else if (changeX > parent.clientWidth - dragItem.clientWidth) { changeX = parent.clientWidth - dragItem.clientWidth } if (changeY < 0) { changeY = 0 } else if (changeY > parent.clientHeight - dragItem.clientHeight) { changeY = parent.clientHeight - dragItem.clientHeight } // 执行挪动 dragItem.style.position = 'absolute' dragItem.style.left = `${changeX}px` dragItem.style.top = `${changeY}px`}
- 第四步:增加鼠标按下事件处理
// 在子元素上监听鼠标按下事件function listenMouseDown(e) { // 批改拖拽状态为拖拽中 dragingState = true const { x, y } = e // 记录鼠标地位 fromX = x fromY = y // 记录元素地位 fromOffsetTop = dragItem.offsetTop fromOffsetLeft = dragItem.offsetLeft}
5.第五布:增加鼠标弹起事件处理
// 在子元素上监听鼠标弹起事件function listenMouseUp() { // 批改拖拽状态为拖拽进行 dragingState = false // 还原父元素状态 parent.style.border = '1px solid transparent'}
6.第六步:对鼠标移入移出父元素做款式凸显
// 当鼠标移入父元素时,对父元素做款式凸显function listenParentMouseEnter(index) { parent.style.boxShadow = '0px 0px 8px #8c8c8c'}// 当鼠标移出父元素时,对父元素做款式重置function listenParentMouseLeave(index) { parent.style.boxShadow = 'none'}