JavaScript实现DOM元素可拖动:原理与常见陷阱

作者:竹影

时间:2026-10-29

浏览:645

本文介绍使用JavaScript实现DOM元素拖拽功能的方法,涵盖element.style.left、offsetLeft及addEventListener等核心知识点。同时针对拖拽过程中第二次操作失效的常见Bug,分析了mousedown、mousemove和mouseup事件的处理逻辑及潜在问题。

文章目录

摘要:

DOM元素拖拽实现原理

近期在项目开发中需要实现图片预览功能,由于用户上传的图片尺寸往往超出当前视图区域,因此决定在固定宽高范围内实现图片的拖动查看功能。基于此需求,编写了一个兼容IE5+、Chrome、Firefox及Opera等主流浏览器的DOM元素拖拽插件。

实现该功能主要涉及以下JavaScript基础知识:

1. 获取元素位置属性 element.style.left

style.left 返回的是一个字符串类型的值,属于可读写变量,修改该值可直接影响元素的布局位置。

2. 获取元素偏移量 element.offsetLeft

offsetLeft 返回的是整数类型的数值,属于只读变量。修改此变量的值不会改变元素的实际布局,仅用于读取当前相对于父级定位元素的偏移距离。

3. 获取鼠标坐标 event.clientX

clientX 事件属性用于返回鼠标指针相对于浏览器页面(或客户区)的水平坐标值,在拖拽计算中用于确定鼠标移动的距离。

4. 操作元素类名 element.className

通过修改 className 可以动态切换元素的CSS类,从而改变样式表现。

上述三点属于较为常见的DOM操作知识,以下重点介绍事件监听机制:

4. 为对象添加事件监控

使用 element.addEventListener("event", "fun", "boolean") 方法注册事件监听器。

event 参数表示要监听的事件类型。

fun 参数表示事件触发后执行的回调函数。

项目开源地址:https://github.com/baixuexiyang/drag

拖拽实例与常见问题分析

实例演示:


var drag = new Drag("test", {
      onStart: function(){

      },
      onMove: function(){
        document.getElementById('position').innerHTML = '距离左边:' + drag.getPositions().left + ';距离顶部:' + drag.getPositions().top;
      },
      onStop: function(){

      }
    });

在实例测试中遇到一个棘手的问题,经过长时间排查仍未找到完美的解决方案。

为了便于测试,将相关代码整合在一个文件中展示。

文件名为 drag.html。


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 
  <title>鼠标拖拽</title> 
  <style type="text/css"> 
    <!-- 
    #dragdiv{ 
      background-color:#0A0909; 
      height:200px; 
      width:157px; 
     
      position:absolute; 
    } 
    .ondrag{ 
      filter:alpha(opacity=200); 
      cursor:move; 
    } 
    .enddrag{ 
      filter:alpha(opacity=100); 
      cursor:default; 
    } 
    #father{ 
      width:600px; 
      height:700px; 
      background:#C63535; 
    } 
    --> 
  </style> 
</head> 
<body> 
  <div id="father"> 
  <div id="dragdiv"></div> 
  </div> 
  <script language="JavaScript"> 
    var dragdiv=document.getElementById("dragdiv"); 
    var father=document.getElementById("father"); 
    var offsetx=0; 
    var offsety=0; 
    var draging=false; 
    function beforeDrag(ev){ 
       
        if (!draging) { 
          draging = true; 
          var l = dragdiv.offsetLeft; 
          var t = dragdiv.offsetTop; 
          offsetx = ev.clientX - l; 
          offsety = ev.clientY - t; 
           
        } 
        else { 
          dragdiv.className = "enddrag"; 
          dragdiv.removeEventListener("mousemove",onDrag); 
          draging = false; 
          return; 
        } 
       
    } 
    function endDrag(){ 
      draging=false; 
      dragdiv.className="enddrag"; 
    } 
    function onDrag(ev){ 
      if (!draging) { 
        dragdiv.className = "enddrag"; 
        return; 
      } 
      else { 
        dragdiv.className = "ondrag"; 
       
        dragdiv.style.left = (ev.clientX - offsetx) + "px"; 
        dragdiv.style.top = (ev.clientY - offsety) + "px"; 
         
      } 
    } 
      dragdiv.addEventListener("mousedown",beforeDrag,true); 
      dragdiv.addEventListener("mousemove",onDrag,false); 
      dragdiv.addEventListener("mouseup",endDrag,true); 
 
  </script> 
 
</body> 
 
</html> 

代码逻辑相对简单,仔细阅读即可理解其基本结构。

第一次拖拽操作非常顺利,按住鼠标即可拖动。然而第二次拖拽时出现异常,必须点击页面其他非拖拽区域重新获取焦点后,才能正常进行第二次拖拽。

以下是涉及的具体鼠标事件说明:

"mousedown" 表示鼠标按键按下时触发,上述代码中触发了 beforeDrag 函数。

"mousemove" 表示鼠标移动时触发,上述代码中触发了 onDrag 函数。

"mouseup" 表示鼠标按键松开时触发,上述代码中触发了 endDrag 函数。

注:网上资料常提及 "onmousedown" 事件名,但笔者实际测试发现该写法无事件响应,使用 "mousedown" 才能正常工作。

针对上述第二次拖拽失效的问题,尝试了多种实验方案,包括调整 addEventListener 的调用顺序以及探讨第三个参数 true/false 所代表的事件捕获与冒泡阶段,但仍未找到完美的解决方法。

问题现象为:"mouseup" 事件在第二次监听时失效,必须通过鼠标点击其他区域重新获取焦点后,拖拽功能才能恢复正常。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章