关于讲解 JS 的拖拽功能的文章数不胜数,我确实没有必要大费周章再写一篇重复的文章来吸引眼球。本文的重点是讲解如何在某些特定的元素上禁止拖拽。这是我在编写插件时遇到的问题,其实很多插件的拖拽功能并没有处理这些细节,经过翻阅 jquery ui 的源码才找到答案。

关于拖拽功能不再啰嗦,直接贴代码

* draggable 拖拽方法 * @param {type} modal - 移动元素 * @param {type} handle - 可拖拽区域 var draggable = function (modal, handle) { var isDragging = false ; var startX = 0 , startY = 0 , left = 0 , top = 0 ; var dragStart = function (e) { var e = e || window.event; e.preventDefault(); isDragging = true ; startX = e.clientX; startY = e.clientY; left = $(modal).offset().left; top = $(modal).offset().top; var dragMove = function (e) { var e = e || window.event; e.preventDefault(); if (isDragging) { var endX = e.clientX, endY = e.clientY, relativeX = endX - startX, relativeY = endY - startY; $(modal).css({ left: relativeX + left + 'px' , top: relativeY + top + 'px' return false ; var dragEnd = function (e) { isDragging = false ; $(handle).on( 'mousedown' , dragStart); $(document).on( 'mousemove' , dragMove); $(document).on( 'mouseup' , dragEnd);

演示 Demo HTML

<div class="modal" id="modal">
  <div class="modal-header">
    <button class="btn-close"><i class="fa fa-times"></i></button>
  </div>
  <div class="modal-body"></div>
</div>

演示 Demo CSS

.modal {
  position: fixed;
  top: 100px;
  left: 100px;
  width: 300px;
  border: 1px solid #aaa;
  padding: 3px;
  border-radius: 5px;
.modal-header {
  height: 24px;
  line-height: 24px;
  background-color: #ddd;
  color: #222;
  padding: 5px;
  border-radius: 3px;
.modal-body {
  height: 100px;
.btn-close {
  width: 24px;
  height: 24px;
  float: right;
  padding: 3px;

演示 Demo JS

draggable('#modal', '#modal .modal-header');

 我们可以通过第二个参数指定不同的拖拽元素,比如可以指定整个 modal 为拖拽元素

draggable('#modal','#modal');

整个拖拽功能并没有太大的问题,但是如果我们拖拽关闭按钮,仍然可以拖拽整个 modal,看起来不太和谐而且在某些情况下会影响功能,所以我们需要排除掉关闭按钮。

排除特定元素的方法

关于如何排除特定元素的方法,很多人会推荐阻止冒泡的方法,但是我试了很多次,这种方法是不行的,因为拖拽事件绑定在了 document 对象上。解决的方法就是在拖拽开始时添加限制条件,代码如下

var dragStart = function(e) { var e = e || window.event; e.preventDefault(); // 获取需要排除的元素 var elemCancel = $(e.target).closest(element); // 如果拖拽的是排除元素,函数返回 if (elemCancel.length) { return true; isDragging = true; startX = e.clientX; startY = e.clientY; left = $(modal).offset().left; top = $(modal).offset().top;

为什么使用 closest() 方法呢?因为我们在排除特定元素的同时也要排除它的子元素。如果使用原生 JS 的话,需要添加获取子元素的方法。以下是完整代码:

* draggable 拖拽方法 * @param {type} modal - 移动元素 * @param {type} handle - 可拖拽区域 * @param {type} cancle - 需要排除的元素 var draggable = function(modal, handle, cancle) { var isDragging = false; var startX = 0, startY = 0, left = 0, top = 0; var dragStart = function(e) { var e = e || window.event; e.preventDefault(); // 获取需要排除的元素 var elemCancel = $(e.target).closest(cancle); // 如果拖拽的是排除元素,函数返回 if (elemCancel.length) { return true; isDragging = true; startX = e.clientX; startY = e.clientY; left = $(modal).offset().left; top = $(modal).offset().top; var dragMove = function(e) { var e = e || window.event; e.preventDefault(); if (isDragging) { var endX = e.clientX, endY = e.clientY, relativeX = endX - startX, relativeY = endY - startY; $(modal).css({ left: relativeX + left + 'px', top: relativeY + top + 'px' return false; var dragEnd = function(e) { isDragging = false; $(handle).on('mousedown', dragStart); $(document).on('mousemove', dragMove); $(document).on('mouseup', dragEnd); View Code

上面的案例的 JS 修改如下:

draggable('#modal','#modal .modal-header', '#modal .btn-close');

其实这个拖拽案例算是 jquery ui 拖拽功能的简单实现。仍然是之前的老话,实现一个功能并不困难,但是如果要把这个功能做好,我们需要考虑很多的细节,或许很多时候我们都把时间花费在调整细节上了。

感谢您的阅读,如果您对我的文章感兴趣,可以关注我的博客,我是叙帝利,下篇文章再见!

开发低代码平台的必备拖拽库 https://github.com/ng-dnd/ng-dnd

基于 Angular Material 的中后台管理框架 https://github.com/ng-matero/ng-matero

Angular Material Extensions 扩展组件库 https://github.com/ng-matero/extensions

仿 Windows 照片查看器插件 https://github.com/nzbin/photoviewer

仿 Windows 照片查看器插件 jQuery 版 https://github.com/nzbin/magnify

完美替代 jQuery 的模块化 DOM 库 https://github.com/nzbin/domq

简化类名的轻量级 CSS 框架 https://github.com/nzbin/snack

与任意 UI 框架搭配使用的通用辅助类 https://github.com/nzbin/snack-helper

单元素纯 CSS 加载动画 https://github.com/nzbin/three-dots

有趣的 jQuery 卡片抽奖插件 https://github.com/nzbin/CardShow

悬疑科幻电影推荐 https://github.com/nzbin/movie-gallery

锻炼记忆力的小程序 https://github.com/nzbin/memory-stake