下面我将为你介绍几种主流的实现方法,从最简单到最灵活,并提供完整的代码示例。

(图片来源网络,侵删)
核心思路
无论使用哪种方法,基本思路都是一致的:
- HTML 结构: 创建一个可拖拽的容器,通常使用 Bootstrap 的
card组件,因为它有标题栏、内容区和阴影,非常适合作为拖拽模块。 - CSS 样式: 为拖拽模块添加基本样式,并定义拖拽过程中的视觉反馈(如改变鼠标指针、阴影等)。
- JavaScript 逻辑: 监听鼠标事件(或触摸事件),当用户在模块标题栏上按下鼠标时,开始拖拽;移动鼠标时,更新模块的位置;松开鼠标时,结束拖拽。
使用原生 JavaScript (最轻量,适合学习原理)
这种方法不依赖任何第三方库,代码量稍多,但能让你完全理解拖拽的实现原理。
实现步骤
- HTML: 创建一个
card作为可拖拽模块,并给它一个唯一的id栏card-header将是我们拖拽的“把手”。 - CSS: 添加一些自定义 CSS 来处理拖拽时的样式,比如改变鼠标光标和提升层级。
- JavaScript: 编写拖拽逻辑。
完整代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Bootstrap 可移动模块 (原生 JS)</title>
<!-- 1. 引入 Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding: 50px; /* 给页面一些内边距 */
}
/* 可拖拽模块的容器,用于定位 */
.draggable-container {
position: relative;
width: 300px;
height: 200px;
}
/* 可拖拽模块本身 */
.draggable-card {
position: absolute; /* 关键:脱离文档流,以便通过 top/left 定位 */
width: 100%;
cursor: move; /* 默认光标 */
user-select: none; /* 防止拖拽时选中文本 */
}
/* 拖拽中的样式 */
.draggable-card.dragging {
opacity: 0.8; /* 半透明 */
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); /* 增强阴影 */
z-index: 1000; /* 提升到最上层 */
cursor: grabbing; /* 抓取光标 */
}
</style>
</head>
<body>
<div class="container">
<h1>可拖拽的 Bootstrap 模块</h1>
<p>拖动下面的卡片标题栏来移动它。</p>
<!-- 可拖拽模块 -->
<div class="draggable-container">
<div id="myCard" class="card draggable-card">
<div class="card-header bg-primary text-white" style="cursor: grab;">
<strong>拖拽我!</strong>
</div>
<div class="card-body">
<p class="card-text">这是一个使用原生 JavaScript 实现的可拖拽 Bootstrap 卡片,你可以在页面内自由移动它。</p>
</div>
</div>
</div>
</div>
<!-- 2. 引入 Bootstrap JS (可选,这里我们主要用原生JS) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const card = document.getElementById('myCard');
const header = card.querySelector('.card-header');
let isDragging = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;
// 鼠标按下事件
header.addEventListener('mousedown', dragStart);
// 鼠标移动事件
document.addEventListener('mousemove', drag);
// 鼠标松开事件
document.addEventListener('mouseup', dragEnd);
// 触摸事件支持 (移动端)
header.addEventListener('touchstart', dragStart);
document.addEventListener('touchmove', drag);
document.addEventListener('touchend', dragEnd);
function dragStart(e) {
if (e.type === "touchstart") {
initialX = e.touches[0].clientX - xOffset;
initialY = e.touches[0].clientY - yOffset;
} else {
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
}
if (e.target === header) {
isDragging = true;
card.classList.add('dragging');
}
}
function drag(e) {
if (isDragging) {
e.preventDefault();
if (e.type === "touchmove") {
currentX = e.touches[0].clientX - initialX;
currentY = e.touches[0].clientY - initialY;
} else {
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
}
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX, currentY, card);
}
}
function dragEnd(e) {
initialX = currentX;
initialY = currentY;
isDragging = false;
card.classList.remove('dragging');
}
function setTranslate(xPos, yPos, el) {
el.style.transform = `translate(${xPos}px, ${yPos}px)`;
}
});
</script>
</body>
</html>
使用 jQuery UI (经典、简单)
如果你的项目已经使用了 jQuery,jQuery UI 提供了非常简单易用的 draggable 组件。
实现步骤
- HTML: 与原生 JS 方法的 HTML 结构类似,但不需要复杂的 CSS。
- 引入库: 引入 jQuery、jQuery UI 的 CSS 和 JS 文件。
- JavaScript: 只需一行代码即可让元素可拖拽。
完整代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Bootstrap 可移动模块 (jQuery UI)</title>
<!-- 1. 引入 Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- 2. 引入 jQuery UI CSS -->
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<style>
body {
padding: 50px;
}
/* 只需要一个容器来限制拖拽范围 */
.draggable-container {
width: 300px;
height: 200px;
border: 1px dashed #ccc; /* 可视化边界 */
}
/* jQuery UI 会自动添加 'ui-draggable' 类 */
.ui-draggable-dragging {
z-index: 1000; /* 确保拖拽时在最上层 */
}
</style>
</head>
<body>
<div class="container">
<h1>可拖拽的 Bootstrap 模块 (jQuery UI)</h1>
<p>拖动下面的卡片标题栏来移动它。</p>
<!-- 可拖拽模块 -->
<div class="draggable-container">
<div id="myCard" class="card">
<div class="card-header bg-success text-white">
<strong>jQuery UI 拖拽我!</strong>
</div>
<div class="card-body">
<p class="card-text">这是一个使用 jQuery UI 实现的可拖拽 Bootstrap 卡片,非常简单!</p>
</div>
</div>
</div>
</div>
<!-- 3. 引入 jQuery -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- 4. 引入 jQuery UI JS -->
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<!-- 5. 引入 Bootstrap JS (可选) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
$(document).ready(function() {
// 只需这一行!
$("#myCard").draggable({ handle: ".card-header" });
// handle: ".card-header" 表示只有点击这个区域才能拖拽,非常实用!
});
</script>
</body>
</html>
使用现代库 interact.js (功能强大,性能好)
interact.js 是一个专注于拖拽、缩放、旋转的轻量级现代库,不依赖 jQuery,性能优秀,API 设计也很优雅。

(图片来源网络,侵删)
实现步骤
- HTML: 结构与前两种方法类似。
- 引入库: 通过 CDN 引入
interact.js。 - JavaScript: 使用
interactAPI 来配置拖拽行为。
完整代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Bootstrap 可移动模块 (interact.js)</title>
<!-- 1. 引入 Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding: 50px;
}
.draggable-container {
width: 300px;
height: 200px;
border: 1px dashed #ccc;
}
/* interact.js 会自动添加 'interact-dragging' 类 */
.interact-dragging {
opacity: 0.8;
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
}
</style>
</head>
<body>
<div class="container">
<h1>可拖拽的 Bootstrap 模块 (interact.js)</h1>
<p>拖动下面的卡片标题栏来移动它。</p>
<!-- 可拖拽模块 -->
<div class="draggable-container">
<div id="myCard" class="card">
<div class="card-header bg-info text-white">
<strong>interact.js 拖拽我!</strong>
</div>
<div class="card-body">
<p class="card-text">这是一个使用 interact.js 实现的可拖拽 Bootstrap 卡片,功能强大且现代!</p>
</div>
</div>
</div>
</div>
<!-- 2. 引入 interact.js -->
<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
<!-- 3. 引入 Bootstrap JS (可选) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
interact('#myCard')
.draggable({
// 指定拖拽手柄
allowFrom: '.card-header',
// 限制在父元素内拖拽
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
// 拖拽时的监听器
listeners: {
// 每次移动时调用
move: dragMoveListener,
// 开始拖拽时调用
start(event) {
event.target.classList.add('interact-dragging');
},
// 结束拖拽时调用
end(event) {
event.target.classList.remove('interact-dragging');
}
}
});
function dragMoveListener(event) {
const target = event.target;
// 保持 transform 的值,并更新 x 和 y
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// 使用 transform 进行移动,性能更好
target.style.transform = `translate(${x}px, ${y}px)`;
// 保存最新的位置
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
});
</script>
</body>
</html>
总结与对比
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 原生 JavaScript | - 无依赖,加载快 - 可控性最高,完全理解原理 |
- 代码量多,需要处理兼容性 - 事件处理逻辑较复杂 |
- 学习和教学 - 对性能和体积有极致要求的项目 - 需要高度定制化拖拽行为 |
| jQuery UI | - 非常简单,一行代码搞定 - 文档丰富,社区支持好 |
- 依赖 jQuery,增加项目体积 - 相对老旧,不符合现代前端趋势 |
- 已经在使用 jQuery 的老项目 - 需要快速实现简单拖拽功能 |
| interact.js | - 轻量,不依赖其他库 - API 现代,功能强大(拖拽、缩放、旋转) - 性能好,支持触摸事件 - 专为交互设计 |
- 相比 jQuery UI 需要学习新的 API | - 现代前端项目(Vue, React, Angular 等) - 需要复杂交互功能(如拼图、看板) - 对移动端支持要求高的项目 |
推荐选择:
- 新项目或对性能有要求:首选
interact.js。 - 快速原型或已有 jQuery 项目:可以使用
jQuery UI。 - 学习和理解原理:从 原生 JavaScript 开始是最好的选择。

(图片来源网络,侵删)
