Sortable.js使用教程:轻量级JS拖拽排序库快速上手

作者:微光时间:2026-11-03 16:35:31浏览:213

本文是一篇详尽实用的Sortable.js快速上手教程。从环境引入、容器初始化、常用配置项详解,到跨列表拖拽、生命周期事件捕获及数据后端持久化,帮助开发者快速掌握这个轻量级JavaScript拖拽排序库。

Sortable.js使用教程:轻量级JS拖拽排序库快速上手
图 0:Sortable.js 核心特点与拖拽交互示意

假设你在开发后台管理系统的自定义菜单、商品图片上传面板或项目任务看板,需要让用户通过直观的拖动来调整显示顺序。若直接编写原生 HTML5 拖拽 API(dragstart、dragover、drop),不仅要手动计算鼠标指针与元素边界坐标、绘制幽灵占位块,还需额外编写触控事件以兼顾移动端设备。Sortable.js 正是为了解决这一繁复问题而诞生的经典工具:它不依赖任何外部框架,压缩体积仅十余千字节,仅需一行核心脚本即可让任意 DOM 列表具备丝滑平移的拖拽排序体验。

一、准备工作与快速引入

在项目中引入 Sortable.js 主要有两种方式:使用 HTML 页面常见的 CDN 链接直接加载,或者在工程化打包环境中使用 npm / yarn 进行模块依赖管理。读者可以根据当前项目的构建方式选择对应方案。

1. CDN 引入(原生 HTML 或传统项目)

如果当前正在维护不需要打包构建的原生页面或后端模板页面,在 <head> 或 <body> 底部加入以下 <script> 标签即可直接使用全局变量 Sortable:

<!-- 引入 Sortable.js 最新稳定版 CDN -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>

2. NPM 依赖安装(Vue / React / Vite 工程)

如果是使用 Vite、Webpack 或各大现代前端框架开发的应用,在终端工作目录下执行安装命令:

# 使用 npm 安装
npm install sortablejs --save

# 或使用 pnpm / yarn
pnpm add sortablejs

安装完成后,在需要启用拖拽的业务组件中导入即可:

import Sortable from 'sortablejs';
Sortable.js使用教程:轻量级JS拖拽排序库快速上手
图 1:Sortable.js 接入与完整业务闭环四步法

二、编写第一个拖拽排序列表

完成引入后,只需在 DOM 树中选择目标列表父节点,调用 new Sortable(el, options) 或 Sortable.create(el, options),即可在当前容器上激活拖拽能力。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Sortable.js 快速示例</title>
  <style>
    .sortable-list {
      width: 320px;
      list-style: none;
      padding: 0;
      margin: 20px 0;
    }
    .sortable-item {
      padding: 12px 16px;
      margin-bottom: 8px;
      background: #f1f5f9;
      border: 1px solid #cbd5e1;
      border-radius: 6px;
      cursor: grab;
      user-select: none;
    }
    /* 拖拽时的占位槽样式 */
    .my-ghost {
      opacity: 0.4;
      background-color: #77B9AE !important;
      border: 2px dashed #142537 !important;
    }
    /* 鼠标按住选中的元素样式 */
    .my-chosen {
      background-color: #e2e8f0;
    }
  </style>
</head>
<body>
  <ul id="my-list" class="sortable-list">
    <li class="sortable-item" data-id="1">项目一:首页轮播图配置</li>
    <li class="sortable-item" data-id="2">项目二:热门推荐模块</li>
    <li class="sortable-item" data-id="3">项目三:底部导航栏设置</li>
  </ul>

  <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
  <script>
    const listEl = document.getElementById('my-list');

    // 初始化 Sortable 实例
    const sortable = Sortable.create(listEl, {
      animation: 150,           // 排序过渡动画时长(单位:毫秒)
      ghostClass: 'my-ghost',   // 占位项自定义样式类名
      chosenClass: 'my-chosen', // 鼠标抓取选中项自定义样式类名
      onEnd: function (evt) {
        console.log('拖拽前索引:', evt.oldIndex);
        console.log('拖拽后新索引:', evt.newIndex);
      }
    });
  </script>
</body>
</html>
提示:如果不传入配置对象 options,Sortable.js 也会以默认参数运行。但默认情况下 animation 为 0(无过渡动画,元素会瞬移),建议在实际业务中始终将其显式设置为 150 到 200 毫秒,以获得自然的平滑流动视觉体验。
Sortable.js使用教程:轻量级JS拖拽排序库快速上手
图 2:Sortable.js 运行期 DOM 结构重排与样式类变化流转

三、常用核心参数全解

Sortable.js 拥有丰富的配置项,能够满足不同界面的交互定制需求。下表列出了日常开发中使用频率最高的核心配置:

参数名 类型 默认值 功能与使用场景
animation Number 0 元素移动排序时的过渡动画时长(毫秒)。设为 150~200 体验最佳。
handle String "" 拖拽手柄 CSS 选择器。限制只有点击该子元素时才能拖动,常用于列表项内有表单或按钮的场景。
filter String "" 禁止拖动的元素选择器。匹配该选择器的子项将无法被拖拽。
ghostClass String "" 占位符样式类。当元素被拖出原位置时,留在原地的虚影所附加的 class。
chosenClass String "" 鼠标按下选中元素时立刻附加的 class。
dragClass String "" 跟随鼠标光标移动的浮动镜像元素附加的 class。
disabled Boolean false 动态禁用或恢复当前容器的拖拽功能。
delay Number 0 按下后需要等待多少毫秒才触发拖拽,常搭配 delayOnTouchOnly: true 用于移动端防止滚动冲突。

使用拖动手柄(Handle)避免点击误触

当列表项内部包含输入框、超链接或操作按钮时,随意点击整行容易误触发拖拽。此时可以通过 handle 限制仅允许抓取专门的图标:

// HTML 结构
<ul id="handle-list">
  <li><span class="drag-handle">☰</span> 菜单设置 <button>删除</button></li>
  <li><span class="drag-handle">☰</span> 权限管理 <button>删除</button></li>
</ul>

// JavaScript 初始化
Sortable.create(document.getElementById('handle-list'), {
  handle: '.drag-handle', // 只有点击包含 .drag-handle 的元素时才触发拖拽
  animation: 150
});

四、进阶特性:跨列表互通与看板拖拽

在看板系统(如“待办 - 进行中 - 已完成”)或商品分类分配场景中,经常需要把一个列表的卡片拖拽移动到另一个列表中。Sortable.js 提供了极其简洁的 group 分组机制来实现这一能力。

Sortable.js使用教程:轻量级JS拖拽排序库快速上手
图 3:跨容器拖拽与 Group 规则流向解析

跨列表配置代码示例

只需为两个列表指定相同的 group 名称,两者的子项便可自由相互拖拽:

// 列表 1:待办箱
const todoList = Sortable.create(document.getElementById('todo-list'), {
  group: 'kanban-group',
  animation: 150
});

// 列表 2:进行中
const inProgressList = Sortable.create(document.getElementById('progress-list'), {
  group: 'kanban-group',
  animation: 150
});

如果业务需要更细粒度的控制(例如:左侧是“素材库”,只能向右侧拖出,但不能把右侧的内容拖回左侧,或者拖出时采用“复制副本”而不是“剪切移动”),可以为 group 传入对象:

// 只能拖出且保留原卡片副本(克隆模式)
Sortable.create(sourceEl, {
  group: {
    name: 'photo-gallery',
    pull: 'clone', // 拖拽时克隆副本
    put: false     // 不允许其他列表的元素放进此列表
  },
  animation: 150
});

五、事件监听与业务数据持久化

在实际生产业务中,拖拽调整顺序只是第一步,关键是将用户拖拽后的最新顺序持久化提交给后端 API 保存。Sortable.js 提供了完善的事件生命周期和快捷获取序列的 API。

1. 核心回调事件

  • onChoose(evt):用户指针按下,选定元素时触发。
  • onStart(evt):拖拽开始移动时触发。
  • onMove(evt, originalEvent):拖拽过程中指针移动经过其他列表项时触发,返回 false 可阻止本次位置交换。
  • onEnd(evt):拖拽结束,DOM 节点已完成重排时触发。核心属性包括:
    • evt.item:被拖动的 DOM 元素。
    • evt.to:目标容器。
    • evt.from:来源容器。
    • evt.oldIndex:拖拽前的原位置索引(从 0 开始)。
    • evt.newIndex:拖拽后落地的新位置索引(从 0 开始)。
  • onAdd(evt):跨列表拖拽时,目标容器收到新元素时触发。
  • onRemove(evt):跨列表拖拽时,源容器失去该元素时触发。

2. 使用 toArray() 获取当前 ID 序列并保存

Sortable.js 内置了 toArray() 方法。当你的 HTML 子节点上设置了 data-id 属性时,该方法会自动按照当前 DOM 顺序返回一个包含所有 ID 的字符串数组:

const sortable = Sortable.create(document.getElementById('category-list'), {
  animation: 150,
  dataIdAttr: 'data-id', // 默认即为 data-id
  onEnd: async function (evt) {
    // 只有当实际位置发生变动时才发起网络请求
    if (evt.oldIndex === evt.newIndex) {
      return;
    }

    // 获取当前列表最新的 ID 数组,例如 ["103", "101", "102"]
    const sortedIds = sortable.toArray();
    console.log('提交最新排序顺序:', sortedIds);

    try {
      const response = await fetch('/api/categories/reorder', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ids: sortedIds })
      });
      if (!response.ok) {
        throw new Error('网络响应异常');
      }
      console.log('排序已成功保存');
    } catch (err) {
      console.error('保存失败:', err);
      // 可在此处调用后端回滚或还原 DOM 顺序
    }
  }
});

六、现代前端框架集成注意事项

当在 Vue 3 或 React 等基于响应式数据驱动的前端框架中使用 Sortable.js 时,必须注意以下关键陷阱:

  • 真实 DOM 与虚拟 DOM(Virtual DOM)脱节:Sortable.js 是直接操作底层真实 DOM 节点的,而 Vue/React 依靠内部虚拟 DOM 树进行渲染。如果在拖拽后不及时更新底层的组件数据数组(如响应式 state),下一次组件重新渲染时,DOM 会立刻被重置回旧状态甚至产生混乱。
  • Vue 方案:推荐直接使用生态中基于 Sortable.js 封装的成熟组件(Vue 3 使用 sortablejs-vue3 或 vuedraggable),它们会在内部自动接管事件并同步双向绑定数据数组。
  • React 方案:在 React 中使用时,一般在 useEffect 内部初始化 Sortable 实例并在组件卸载时调用 sortable.destroy()。在 onEnd 回调中,通过计算 oldIndex 和 newIndex 执行数组位置交换,再调用 setItems([...newItems]) 触发状态更新。
Sortable.js使用教程:轻量级JS拖拽排序库快速上手
图 4:Sortable.js 完整功能体系与选型应用指南

七、总结

Sortable.js 凭借小巧的体积、零第三方依赖以及出色的移动触控兼容性,成为前端开发中实现列表拖拽与看板排序的首选类库。在日常项目中,通过掌握基础容器初始化、animation 动画设置、group 跨列表协作以及 onEnd 数据提取这几个核心知识点,就能在短时间内搭建出交互平滑、稳定可靠的拖拽排序功能。

作者最新文章
相关文章
更多