乐趣区

关于javascript:浏览器鼠标事件原生api实现拖拽功能

浏览器鼠标事件原生 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`
}
  1. 第四步:增加鼠标按下事件处理
// 在子元素上监听鼠标按下事件
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'}
退出移动版