ele-drag
Version:
一个简单易用的js拖动库
283 lines (204 loc) • 5.97 kB
Markdown
# Dragable.js - 轻量级跨平台拖动库
## 简介
Dragable.js 是一个简单易用的 JavaScript 拖动库,支持移动端和电脑端触摸/鼠标事件。它通过扩展 HTMLElement 原型提供了直观的 API,无需复杂配置即可实现元素的拖动功能。
## 安装与引入
### CDN 引入
```html
<!-- 通过 unpkg 引入 -->
<script src="https://unpkg.com/dragable-js"></script>
<!-- 或通过 jsdelivr 引入 -->
<script src="https://cdn.jsdelivr.net/npm/dragable-js"></script>
```
### npm 安装
```bash
npm install dragable-js
```
然后通过模块系统引入:
```javascript
import 'dragable-js'; // 全局注册
// 或
import { enableDrag, disableDrag } from 'dragable-js'; // 按需引入
```
## 基本使用
### 启用拖动
```javascript
// 获取元素
const element = document.getElementById('drag-me');
// 启用拖动
element.enableDrag();
```
### 禁用拖动
```javascript
// 禁用拖动
element.disableDrag();
```
## 高级配置
### 拖动限制
你可以通过 CSS 或 JavaScript 限制拖动范围:
```css
#drag-me {
position: absolute;
/* 限制在父容器内拖动 */
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
width: 100px;
height: 100px;
}
```
### 自定义拖动句柄
如果你想只在特定子元素上触发拖动:
```javascript
const handle = element.querySelector('.drag-handle');
handle.addEventListener('mousedown', (e) => {
e.preventDefault();
element.enableDrag();
});
document.addEventListener('mouseup', () => {
element.disableDrag();
});
```
## 事件系统
Dragable.js 提供了完整的事件生命周期:
### dragstart
拖动开始时触发
```javascript
element.addEventListener('dragstart', (e) => {
console.log('开始拖动', e.detail);
// e.detail 包含 { x, y } 起始坐标
});
```
### dragmove
拖动过程中持续触发
```javascript
element.addEventListener('dragmove', (e) => {
console.log('拖动中', e.detail);
// e.detail 包含 { x, y, left, top } 当前坐标和位置
});
```
### dragend
拖动结束时触发
```javascript
element.addEventListener('dragend', () => {
console.log('拖动结束');
});
```
## 样式定制
当元素被拖动时,会自动添加 `dragging` 类,你可以利用这个类添加视觉效果:
```css
.dragging {
opacity: 0.8;
cursor: grabbing;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transition: none; /* 拖动时禁用过渡效果 */
}
/* 拖动句柄样式 */
.drag-handle {
cursor: grab;
}
.drag-handle:active {
cursor: grabbing;
}
```
## 最佳实践
### 1. 性能优化
对于大量可拖动元素,建议:
```javascript
// 批量启用拖动
document.querySelectorAll('.draggable-item').forEach(item => {
item.enableDrag();
});
// 使用事件委托处理拖动事件
document.addEventListener('dragmove', (e) => {
if (e.target.classList.contains('important-item')) {
// 特殊处理
}
});
```
### 2. 移动端适配
确保添加以下 meta 标签防止浏览器默认行为:
```html
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
```
### 3. 无障碍访问
为可拖动元素添加 ARIA 属性:
```html
<div id="drag-me" aria-grabbed="false" tabindex="0">
可拖动元素
</div>
```
并通过 JavaScript 更新状态:
```javascript
element.addEventListener('dragstart', () => {
element.setAttribute('aria-grabbed', 'true');
});
element.addEventListener('dragend', () => {
element.setAttribute('aria-grabbed', 'false');
});
```
## API 参考
### HTMLElement 原型方法
| 方法 | 描述 | 示例 |
|------|------|------|
| `enableDrag()` | 启用元素拖动功能 | `element.enableDrag()` |
| `disableDrag()` | 禁用元素拖动功能 | `element.disableDrag()` |
### 自定义事件
| 事件 | 触发时机 | 事件详情 |
|------|----------|----------|
| `dragstart` | 拖动开始时触发 | `{ x, y }` 起始坐标 |
| `dragmove` | 拖动过程中持续触发 | `{ x, y, left, top }` 当前坐标和位置 |
| `dragend` | 拖动结束时触发 | 无 |
## 常见问题
### Q: 拖动时页面也跟着滚动怎么办?
A: 确保在可滚动容器中使用,或添加以下 CSS:
```css
body {
overflow: hidden;
}
```
### Q: 如何限制拖动范围?
A: 在 `dragmove` 事件中检查并修正位置:
```javascript
element.addEventListener('dragmove', (e) => {
const { left, top } = e.detail;
const maxX = window.innerWidth - element.offsetWidth;
const maxY = window.innerHeight - element.offsetHeight;
element.style.left = `${Math.max(0, Math.min(left, maxX))}px`;
element.style.top = `${Math.max(0, Math.min(top, maxY))}px`;
});
```
### Q: 如何实现磁贴吸附效果?
A: 在 `dragend` 事件中处理:
```javascript
element.addEventListener('dragend', () => {
const rect = element.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
// 找到最近的吸附点
const snapPoints = [...]; // 你的吸附点数组
const closest = snapPoints.reduce((prev, curr) => {
const prevDist = Math.hypot(prev.x - centerX, prev.y - centerY);
const currDist = Math.hypot(curr.x - centerX, curr.y - centerY);
return currDist < prevDist ? curr : prev;
});
// 动画到吸附点
element.style.transition = 'all 0.3s ease';
element.style.left = `${closest.x - rect.width / 2}px`;
element.style.top = `${closest.y - rect.height / 2}px`;
setTimeout(() => {
element.style.transition = '';
}, 300);
});
```
## 版本更新
### v1.0.1
- 修复了移动端多点触控的问题
- 提高了事件处理的性能
### v1.0.0
- 初始发布版本
- 支持基础拖动功能
- 跨平台触摸/鼠标事件支持
## 许可证
MIT License - 免费用于个人和商业项目