interact.js logo

interact.js

功能最全面的 JavaScript 交互库,唯一同时支持拖拽、缩放和旋转手势的主流解决方案。

拖拽排序拖拽库手势交互开源

功能全面的 JavaScript 交互库,唯一同时支持拖拽、缩放和旋转手势的主流解决方案,适用于画布、仪表盘、图片编辑器等复杂交互场景。

interact.js

功能最全面的 JavaScript 交互库,唯一同时支持拖拽、缩放和旋转手势的主流解决方案。

技术简介说明

interact.js 是一款功能全面的 JavaScript 交互库,由 Taye Ogunmade 创建,专注于拖拽(Drag)、缩放(Resize)和手势(Gesture)三大交互能力。它是主流库中唯一同时支持拖拽+缩放+旋转手势的解决方案,在画布/白板应用、仪表盘编辑器、图片编辑器等场景具有不可替代的地位。

与传统拖拽排序库不同,interact.js 本身不做任何排序。它提供原始的指针事件数据和位移增量(dx/dy),由开发者决定如何实现视觉反馈。这种"提供数据、不操作 UI"的设计哲学使其具有极高的灵活性,但也意味着列表排序等常见场景需要开发者自行实现逻辑。

interact.js 采用模块化架构,支持 tree-shaking 的 scoped packages,核心功能可按需导入。库体积约 40KB(gzip),支持现代浏览器 + IE9+,内建 TypeScript 类型定义。经过 10+ 年迭代,核心功能成熟稳定,npm 周下载量约 57 万次。

基本信息

快速上手

安装

# npm
npm install interactjs --save
 
# 或 CDN
<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
 
# 模块化导入(推荐)
npm install @interactjs/interact

基础配置

import interact from 'interactjs'
 
// 使元素可拖拽
interact('.draggable').draggable({
  // 启用惯性
  inertia: true,
  // 限制在父元素内
  modifiers: [
    interact.modifiers.restrict({
      restriction: 'parent',
    }),
  ],
  autoScroll: true,
  listeners: {
    move: dragMoveListener,
  },
})
 
function dragMoveListener(event) {
  const target = event.target
  const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
  const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy
 
  target.style.transform = `translate(${x}px, ${y}px)`
  target.setAttribute('data-x', x)
  target.setAttribute('data-y', y)
}

最小示例

<!DOCTYPE html>
<html>
<head>
  <style>
    #drag-me {
      width: 200px;
      height: 200px;
      background: #4CAF50;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: move;
      touch-action: none; /* 防止拖拽时触发页面滚动 */
    }
  </style>
</head>
<body>
  <div id="drag-me">拖拽我!</div>
 
  <script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
  <script>
    interact('#drag-me')
      .draggable({
        listeners: {
          move(event) {
            const target = event.target
            const x = (parseFloat(target.dataset.x) || 0) + event.dx
            const y = (parseFloat(target.dataset.y) || 0) + event.dy
            target.style.transform = `translate(${x}px, ${y}px)`
            target.dataset.x = x
            target.dataset.y = y
          }
        }
      })
      // 使元素可缩放
      .resizable({
        edges: { top: true, left: true, bottom: true, right: true },
        listeners: {
          move(event) {
            const target = event.target
            target.style.width = `${event.rect.width}px`
            target.style.height = `${event.rect.height}px`
          }
        }
      })
  </script>
</body>
</html>

核心概念与架构

架构设计

interact.js 的架构围绕交互类型修饰器两个核心维度构建:

┌─────────────────────────────────────────┐
│              interact()                  │
│         (核心函数,返回 Interactable)     │
├─────────────────────────────────────────┤
│                                         │
│  交互类型:                               │
│  ┌─────────┐ ┌──────────┐ ┌──────────┐ │
│  │draggable│ │resizable │ │gesturable│ │
│  │(拖拽)   │ │(缩放)    │ │(手势)    │ │
│  └────┬────┘ └────┬─────┘ └────┬─────┘ │
│       │           │            │        │
│  ┌────▼───────────▼────────────▼─────┐ │
│  │          Pointer Events           │ │
│  │    (统一鼠标/触摸/指针事件)        │ │
│  └───────────────────────────────────┘ │
│                                         │
│  修饰器 (Modifiers):                     │
│  ┌────────┐ ┌──────────┐ ┌───────────┐ │
│  │  snap  │ │ restrict │ │aspectRatio│ │
│  │(吸附)  │ │(限制范围) │ │(宽高比)   │ │
│  └────────┘ └──────────┘ └───────────┘ │
│                                         │
│  投放区 (Dropzone):                      │
│  ┌──────────┐                           │
│  │ dropzone │ ← 定义可接受的投放目标     │
│  └──────────┘                           │
│                                         │
│  辅助:                                   │
│  ┌──────────────┐ ┌─────────────┐       │
│  │  auto-scroll │ │   inertia   │       │
│  │  (自动滚动)  │ │   (惯性)    │       │
│  └──────────────┘ └─────────────┘       │
└─────────────────────────────────────────┘

核心交互类型

交互类型说明API 入口
拖拽 (Drag)元素在页面内自由移动.draggable()
缩放 (Resize)调整元素尺寸.resizable()
手势 (Gesture)多点触控的旋转和缩放.gesturable()
投放区 (Dropzone)定义可接受的投放目标.dropzone()
指针事件统一的 tap/hold/doubletap 事件.on('tap'), .on('hold')

事件模型

  • 统一 API:鼠标和触摸事件使用相同接口处理
  • 事件生命周期startmoveend
  • 多交互支持:多个元素可以同时被交互
  • 事件对象关键属性
    • event.dx / event.dy — 位移增量
    • event.rect / event.deltaRect — 尺寸信息(缩放时)
    • event.da — 角度变化(手势旋转时)
    • event.scale — 缩放比例(手势缩放时)
    • event.pageX / event.pageY — 指针位置

修饰器系统 (Modifiers)

修饰器是 interact.js 最强大的特性之一,用于动态约束交互行为:

修饰器功能说明
snap吸附吸附到网格、特定点或自定义函数
restrict限制范围限制在父元素、矩形区域或自定义边界内
aspectRatio保持宽高比缩放时保持比例,可在交互中切换开关
endOnly仅结束时执行仅在交互结束时执行修饰器

修饰器通过数组传入,按顺序依次执行,顺序可能影响最终结果:

interact('.element').draggable({
  modifiers: [
    interact.modifiers.snap({
      targets: [interact.snappers.grid({ x: 20, y: 20 })],
    }),
    interact.modifiers.restrict({
      restriction: 'parent',
    }),
  ],
})

核心特性

  • 拖拽 + 缩放 + 旋转三合一:唯一同时支持三大交互的主流库,适合需要复合交互的应用
  • 统一指针事件:鼠标、触摸、指针事件统一抽象,无需分别处理
  • 强大的修饰器系统:snap(吸附)、restrict(限制)、aspectRatio(宽高比)可自由组合
  • 惯性 (Inertia):拖拽结束后模拟物理惯性运动,提升交互体验
  • 多点触控手势:支持双指旋转、缩放手势,触摸设备友好
  • HTML 和 SVG 支持:包括嵌入在 &lt;object&gt; 中的 SVG
  • 模块化架构:scoped packages 支持 tree-shaking,按需导入
  • 自动滚动:拖拽到容器边缘时自动滚动(需手动启用)
  • 投放区 (Dropzone):定义可接受的投放目标,支持拖拽放置
  • 事件重放 (Reflow):可强制重新执行修饰器和监听器,用于动态更新
  • CSS transform 支持:通过 data-x/data-y 和 CSS transform 实现高性能平移

生态图

                    ┌──────────────────┐
                    │    interactjs    │  ← 核心库
                    │    v1.10.27      │
                    └────────┬─────────┘
                             │
            ┌────────────────┼────────────────┐
            │                │                │
   ┌────────▼──────┐ ┌──────▼───────┐ ┌──────▼────────┐
   │ @interactjs/  │ │ @interactjs/ │ │ @interactjs/  │
   │ actions       │ │ modifiers    │ │ inertia       │
   │ (拖拽/缩放/   │ │ (约束系统)   │ │ (物理惯性)    │
   │  手势行为)    │ │              │ │               │
   └───────────────┘ └──────────────┘ └───────────────┘

   模块化包:
   ┌──────────────────────────────────────────────┐
   │ • @interactjs/interact    (核心函数)         │
   │ • @interactjs/actions     (拖拽/缩放/手势)   │
   │ • @interactjs/auto-start  (指针移动触发)     │
   │ • @interactjs/modifiers   (约束系统)         │
   │ • @interactjs/snappers    (网格工具)         │
   │ • @interactjs/inertia     (物理惯性)         │
   │ • @interactjs/reflow      (事件重放)         │
   │ • @interactjs/auto-scroll (自动滚动)         │
   │ • @interactjs/dev-tools   (开发工具)         │
   │ • @interactjs/types       (TypeScript 类型)  │
   └──────────────────────────────────────────────┘

   社区框架集成:
   ┌──────────────────────────────────────────────┐
   │ • vue-interactjs (Vue 组件封装)              │
   │ • reactablejs (React 高阶组件封装)           │
   │ • 多种框架集成方案                            │
   └──────────────────────────────────────────────┘

适用场景

  • 画布/白板应用:自由拖拽元素 + SVG 支持,核心能力完美匹配
  • 仪表盘/编辑器布局:拖拽调整面板位置 + 缩放调整面板尺寸
  • 图片/视频编辑器:拖拽定位 + 缩放尺寸 + 旋转角度
  • 自由拖拽元素:将元素拖到页面任意位置(非排序语义)
  • 自定义吸附/约束:修饰器系统极其灵活,支持网格吸附、边界限制、宽高比保持
  • 需要复合交互的场景:同一元素同时需要拖拽+缩放+旋转
  • 仪表盘拖拽布局:需要手动实现布局逻辑(如 grid 对齐)

开发与工程化

开发流程

# 克隆仓库
git clone https://github.com/taye/interact.js.git
cd interact.js
 
# 安装依赖
npm install
 
# 开发模式
npm run dev
 
# 构建
npm run build
 
# 测试
npm test

项目结构

interact.js/
├── packages/
│   ├── core/               # 核心事件处理
│   ├── actions/            # 拖拽、缩放、手势行为
│   ├── modifiers/          # 约束系统(snap、restrict 等)
│   ├── snappers/           # 网格工具函数
│   ├── inertia/            # 物理惯性模拟
│   ├── auto-scroll/        # 自动滚动
│   ├── auto-start/         # 通过指针移动触发动作
│   ├── reflow/             # 修饰器/监听器重放
│   ├── dev-tools/          # 开发警告与构建优化
│   ├── types/              # TypeScript 类型定义
│   └── interact/           # 核心函数
├── test/                    # 测试文件
└── dist/                    # 构建输出

构建与部署

  • 输出 ES2018 兼容代码
  • 支持 ESM 和 UMD 格式
  • 支持 tree-shaking(通过 scoped packages)

性能与安全

性能特点

  • 模块化可 tree-shake:按需导入减少包体积
  • 底层指针事件抽象:无多余 DOM 操作
  • 不主动操作 DOM:开发者控制渲染方式,避免不必要的重排
  • CSS transform 优先:推荐使用 transform 而非 top/left,保持 GPU 加速

性能优化建议

  1. 使用 CSS transform 而非 top/left

    // ✅ 推荐:使用 transform,性能更好
    target.style.transform = `translate(${x}px, ${y}px)`
    // ❌ 避免:触发重排
    // target.style.top = `${y}px`
  2. 模块化导入减少体积

    import interact from '@interactjs/interact'
    import drag from '@interactjs/actions/drag'
    import modifiers from '@interactjs/modifiers'
  3. 正确清理实例:防止内存泄漏

    const interaction = interact('.element').draggable({...})
    // 移除元素时必须调用
    interaction.unset()
  4. auto-scroll 按需启用:默认关闭,仅需要时手动启用

安全注意事项

  • interact.js 不涉及用户输入,无 XSS 风险
  • 注意 DOM 元素移除后调用 unset() 防止内存泄漏
  • 拖拽坐标数据避免包含敏感信息

已知性能瓶颈

瓶颈说明
复杂 SVG 拖拽卡顿多层 SVG 元素拖拽时性能下降(Issue #770
内存泄漏风险DOM 元素移除后未正确 unset() 导致元素无法 GC(Issue #713
隐藏 dropzone 消耗滚动容器中不可见的 dropzone 仍保持活跃(Issue #694
CSS transform 缩放冲突父元素有 scale() 时拖拽坐标计算不准确(Issue #137

技术对比

与交互/拖拽库对比

特性interact.jsHammer.jsDragulaSortableJSdnd-kit
拖拽
缩放
旋转手势
触摸手势✅ (最专业)
列表排序需手写✅ (最佳)
修饰器/约束✅ (强大)有限
惯性
SVG 支持
维护状态⚠️ 低活跃❌ 不活跃❌ 不活跃维护模式✅ 活跃
React 友好度一般一般一般一般优秀
包体积~40KB~7KB~5KB~30KB~6KB

选型建议

场景推荐
拖拽 + 缩放 + 旋转一体interact.js(唯一选择)
列表排序SortableJS 或 dnd-kit
触摸手势识别Hammer.js(但已不活跃)
React 项目dnd-kit(更贴合 React 范式)
画布/白板interact.js(SVG 支持 + 自由定位)
简单拖拽interact.js 大材小用

最佳实践

生产环境最佳实践

  1. 移动端必须设置 touch-action: none

    .draggable-element {
      touch-action: none; /* 防止拖拽时触发页面滚动 */
    }
  2. 使用 CSS transform 而非 top/left

    // ✅ 推荐:transform 性能更好,走 GPU 合成层
    target.style.transform = `translate(${x}px, ${y}px)`
    // ❌ 避免:触发重排
    // target.style.top = `${y}px`
  3. 正确清理实例

    const interaction = interact('.element').draggable({...})
    // 移除元素时必须调用,防止内存泄漏
    interaction.unset()
  4. 修饰器组合顺序很重要

    interact('.element').draggable({
      modifiers: [
        interact.modifiers.snap({ targets: [...] }),      // 先吸附
        interact.modifiers.restrict({ restriction: 'parent' }), // 再限制
      ],
    })
  5. 模块化导入减少体积

    import interact from '@interactjs/interact'
    import drag from '@interactjs/actions/drag'
    import resize from '@interactjs/actions/resize'
  6. 缩放时保持宽高比

    interact('.resize-me').resizable({
      modifiers: [
        interact.modifiers.aspectRatio({ ratio: 'preserve' }),
      ],
    })
  7. 拖拽手柄 + 缩放共存

    interact('.widget')
      .draggable({ handle: '.widget-header' })
      .resizable({ edges: { bottom: true, right: true } })

常见陷阱

陷阱说明解决方案
移动端拖拽同时滚动页面touchmove 事件未阻止设置 touch-action: none
CSS scale 导致坐标偏移父元素有 transform: scale()避免在交互元素上使用 CSS scale,或使用补偿计算
iOS 偶发失效iOS 设备随机停止工作(Issue #549确保正确初始化和清理实例
snap + restrict 定位偏差两者同时使用时可能冲突(Issue #554调整修饰器顺序和参数
内存泄漏DOM 移除后未 unset()组件卸载时调用 interaction.unset()
drag handle + resize 配置复杂手柄与缩放共存需要额外配置(Issue #402仔细配置 handleedges

技术局限与边界

已知限制

限制说明
CSS transform 缩放冲突父元素有 scale() 时拖拽坐标计算不准确
移动端 scroll/drag 冲突拖拽时页面同时滚动,需手动处理 touch-action
iOS 偶发失效在 iOS 设备上可能随机停止工作
无内建虚拟化大量可拖拽元素时无自动优化
无列表排序能力需手写排序逻辑,不如 SortableJS 开箱即用
无全局作用域隔离多个实例共享全局状态
开发维护节奏放缓自 2024 年 3 月以来无新版本发布(超 2 年)
React 友好度一般需要手动管理实例生命周期,不如 dnd-kit 贴合 React 范式
学习曲线较陡修饰器系统、事件模型需要理解多个概念

不适用场景

  • 简单列表排序 → 推荐 SortableJS 或 dnd-kit(开箱即用)
  • 纯 React 项目 → 推荐 dnd-kit(React 原生集成)
  • 看板/卡片拖拽排序 → 推荐 dnd-kit 或 SortableJS
  • 纯触摸手势识别 → Hammer.js 更专业(但已不活跃)

学习资源

2026 年现状

维护状态评估

指标状态
最新版本v1.10.27(2024 年 3 月 28 日)
距上次发布超过 2 年
维护节奏2023-2024 年初密集发布了 10 个补丁版本,之后停滞
npm 周下载量~57 万/周(大量存量项目)
GitHub Stars~12,900+
Twitter/X@interactjs 自 2022 年 3 月后无更新
维护状态⚠️ 稳定/低活跃

近期版本变更摘要

版本主要变更
v1.10.27修复 skipLibCheck: false 时的 TypeScript 问题
v1.10.26改进构建流程,验证 ES2018 兼容性
v1.10.25输出改为 ES5 语法
v1.10.24生成 API 文档
v1.10.23修复 nullish coalescing 和 symbol-tree 构建问题
v1.10.22修复启用 inertia 时的手势错误
v1.10.21修复 drop 事件目标的回归问题
v1.10.20导入插件支持模块增强
v1.10.18移除 types 依赖、支持 aspectRatio 修饰器切换、修复 ESM 导出

发展趋势

  • 稳定但低活跃:核心功能成熟,但新功能开发停滞
  • 无明确 v2 路线图:社区未见重大架构升级计划
  • 存量用户庞大:57 万周下载量说明广泛使用
  • 新项目选型分化:React 项目推荐 dnd-kit;拖拽+缩放需求 interact.js 仍是最佳选择
  • 被逐步替代:新项目推荐中逐渐被 dnd-kit、SortableJS 等替代

选型结论

interact.js 在 2026 年处于「稳定/低活跃」状态(超 2 年无新版本)。 当需要拖拽 + 缩放 + 旋转手势一体化时,它仍是唯一的主流选择。但如果是纯拖拽排序场景,推荐使用更专注的库(SortableJS、dnd-kit)。新项目选型需谨慎评估维护风险。