30KB 轻量王者!SortableJS 轻松搞定拖拽需求

作为一名每天和 DOM 打交道的前端程序员,我深知在项目中实现拖拽排序功能的痛点 ------ 自己手写不仅要处理复杂的鼠标 / 触摸事件,还要考虑兼容性和性能问题。直到我接触到了SortableJS,这个轻量级且功能强大的库彻底改变了我处理拖拽需求的方式。今天就从实际开发角度,带大家全面了解 SortableJS,并通过代码实例演示其核心用法。

Sortable.js中文网

一、SortableJS 是什么?

SortableJS 是一款无依赖(不依赖 jQuery、Vue 等框架)的 JavaScript 拖拽排序库,支持 PC 端和移动端,兼容所有现代浏览器,甚至包括 IE11。它的核心优势在于:

  • 轻量:压缩后仅 30KB 左右,不会给项目带来额外负担;

  • 灵活:支持列表、表格、网格等多种布局的拖拽,可自定义拖拽样式、触发条件和回调函数;

  • 易用:API 设计简洁,只需几行代码就能实现基础拖拽功能;

  • 生态好:有专门针对 Vue、React、Angular 等框架的适配版本(如 vue-sortablejs),无缝融入现有项目。

在实际工作中,我曾用它实现过 "任务看板拖拽""表格列顺序调整""多列表数据迁移" 等需求,效率比手写方案提升了至少 50%。

二、基础使用:从一个简单列表开始

首先我们来看最常见的场景 ------ 单列表拖拽排序。假设项目中有一个待办事项列表,需要支持拖拽调整顺序,步骤如下:

1. 引入 SortableJS

有两种引入方式,可根据项目环境选择:

  • CDN 引入(适合快速测试或小型项目):
xml 复制代码
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
  • npm 安装(适合工程化项目):
css 复制代码
npm install sortablejs --save

在 Vue/React 组件中引入:

javascript 复制代码
import Sortable from 'sortablejs';

2. 基础 HTML 结构

先创建一个简单的待办列表 DOM:

xml 复制代码
<!-- 待办列表 -->
<ul id="todoList" class="todo-list">
  <li class="todo-item">完成SortableJS文档阅读</li>
  <li class="todo-item">编写拖拽排序示例代码</li>
  <li class="todo-item">测试移动端兼容性</li>
  <li class="todo-item">提交代码到GitHub</li>
</ul>

3. 初始化 Sortable

只需一行核心代码即可初始化拖拽功能,再通过配置项自定义体验:

javascript 复制代码
// 获取列表DOM元素
const todoList = document.getElementById('todoList');
// 初始化Sortable
const sortable = new Sortable(todoList, {
  // 1. 基础配置
  animation: 150, // 拖拽时的动画时长(毫秒),提升视觉体验
  handle: '.todo-item', // 拖拽触发区域(这里整个列表项都可拖拽)
  ghostClass: 'todo-item-ghost', // 拖拽时"幽灵"元素的类名(用于自定义样式)
  
  // 2. 回调函数:处理拖拽后的逻辑(如更新数据)
  onEnd: (evt) => {
    // evt包含拖拽相关信息:
    // oldIndex:元素原来的位置索引
    // newIndex:元素新的位置索引
    // item:被拖拽的DOM元素
    console.log(`待办项从位置 ${evt.oldIndex} 移动到 ${evt.newIndex}`);
    
    // 实际项目中,这里需要更新数据(如接口请求保存新顺序)
    // 示例:假设我们有一个todoData数组,更新其顺序
    const movedItem = todoData.splice(evt.oldIndex, 1)[0];
    todoData.splice(evt.newIndex, 0, movedItem);
    console.log('更新后的待办数据:', todoData);
  }
});

4. 自定义拖拽样式

通过 CSS 美化拖拽过程中的视觉效果:

css 复制代码
.todo-list {
  list-style: none;
  padding: 0;
  width: 300px;
}
.todo-item {
  padding: 12px 16px;
  margin-bottom: 8px;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 4px;
  cursor: move; /* 鼠标悬浮时显示"移动"光标 */
  transition: all 0.2s;
}
/* 拖拽时"幽灵"元素的样式(半透明、灰色) */
.todo-item-ghost {
  opacity: 0.5;
  background-color: #f3f4f6;
}
/* 拖拽过程中,被拖拽元素的样式(可选) */
.todo-item.sortable-ghost {
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

到这里,一个基础的拖拽排序列表就完成了。在实际开发中,我会根据需求调整handle(比如只允许通过 "拖拽图标" 触发)、animation时长等配置,让交互更符合产品设计。

三、进阶场景:表格拖拽与多列表交互

SortableJS 的能力远不止单列表排序,下面两个场景在工作中也非常常见,我们结合代码实例来看。

场景 1:表格列拖拽调整顺序

在数据表格中,用户常需要自定义列的显示顺序,SortableJS 可以轻松实现:

xml 复制代码
<!-- 数据表格 -->
<table id="dataTable" class="data-table">
  <thead>
    <tr>
      <th class="table-header">ID</th>
      <th class="table-header">姓名</th>
      <th class="table-header">部门</th>
      <th class="table-header">入职时间</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>1</td><td>张三</td><td>产品部</td><td>2023-01-15</td></tr>
    <tr><td>2</td><td>李四</td><td>研发部</td><td>2023-03-22</td></tr>
    <!-- 更多行... -->
  </tbody>
</table>
ini 复制代码
// 初始化表格列拖拽(注意:目标是thead中的tr)
const tableHeader = document.querySelector('#dataTable thead tr');
new Sortable(tableHeader, {
  animation: 150,
  ghostClass: 'header-ghost',
  // 关键:只允许横向拖拽(表格列不需要纵向移动)
  axis: 'x',
  onEnd: (evt) => {
    const columnIndex = evt.newIndex;
    console.log(`表格列调整到第 ${columnIndex + 1} 位`);
    // 实际项目中:需要同步调整tbody中对应列的数据
    const tbodyRows = document.querySelectorAll('#dataTable tbody tr');
    tbodyRows.forEach(row => {
      const cells = row.querySelectorAll('td');
      const movedCell = cells[evt.oldIndex];
      row.removeChild(movedCell);
      row.insertBefore(movedCell, cells[evt.newIndex]);
    });
  }
});

场景 2:多列表之间的拖拽(如看板)

在 "任务看板" 场景中,常需要将任务从 "待办" 拖拽到 "进行中" 或 "已完成",SortableJS 通过group配置实现多列表交互:

xml 复制代码
<!-- 看板容器 -->
<div class="kanban-board">
  <!-- 待办列 -->
  <div class="kanban-column" id="todoColumn">
    <h3>待办</h3>
    <div class="task">任务1:需求分析</div>
  </div>
  <!-- 进行中列 -->
  <div class="kanban-column" id="doingColumn">
    <h3>进行中</h3>
    <div class="task">任务2:UI设计</div>
  </div>
  <!-- 已完成列 -->
  <div class="kanban-column" id="doneColumn">
    <h3>已完成</h3>
  </div>
</div>
javascript 复制代码
// 多列表拖拽的核心:所有列使用相同的group名称
const createKanbanSortable = (columnId) => {
  const column = document.getElementById(columnId);
  return new Sortable(column, {
    animation: 150,
    group: {
      name: 'kanban-group', // 相同group名称的列表可互相拖拽
      pull: true, // 允许从当前列表拖拽出去
      put: true // 允许从其他列表拖拽进来
    },
    handle: '.task',
    onEnd: (evt) => {
      // 区分"同列表排序"和"跨列表拖拽"
      if (evt.from !== evt.to) {
        // 跨列表拖拽:更新任务状态(如从"待办"到"进行中")
        const taskName = evt.item.textContent;
        const fromColumn = evt.from.querySelector('h3').textContent;
        const toColumn = evt.to.querySelector('h3').textContent;
        console.log(`任务「${taskName}」从「${fromColumn}」移动到「${toColumn}」`);
        // 实际项目中:这里需要调用接口更新任务状态
      } else {
        // 同列表排序:仅更新顺序
        console.log(`任务在「${evt.to.querySelector('h3').textContent}」中调整顺序`);
      }
    }
  });
};
// 初始化三个看板列
createKanbanSortable('todoColumn');
createKanbanSortable('doingColumn');
createKanbanSortable('doneColumn');

四、框架适配:以 Vue3 为例

如果你的项目基于 Vue3 开发,可使用专门的适配库vue-sortablejs,用法更贴合 Vue 的语法:

  1. 安装依赖:
css 复制代码
npm install vue-sortablejs sortablejs --save
  1. 在组件中使用:
xml 复制代码
<template>
  <ul v-sortable="sortableOptions" class="todo-list">
    <li v-for="(item, index) in todoData" :key="index" class="todo-item">
      {{ item }}
    </li>
  </ul>
</template>
<script setup>
import { ref } from 'vue';
import { vSortable } from 'vue-sortablejs';
// 响应式数据
const todoData = ref([
  '完成SortableJS文档阅读',
  '编写拖拽排序示例代码',
  '测试移动端兼容性'
]);
// Sortable配置项
const sortableOptions = {
  animation: 150,
  ghostClass: 'todo-item-ghost',
  onEnd: (evt) => {
    // 直接操作响应式数据,Vue会自动更新DOM
    const movedItem = todoData.value.splice(evt.oldIndex, 1)[0];
    todoData.value.splice(evt.newIndex, 0, movedItem);
  }
};
</script>

五、工作中的避坑指南

在实际使用 SortableJS 时,我踩过几个小坑,分享给大家:

  1. 拖拽元素内有输入框 :如果列表项包含或,拖拽时可能会触发输入框聚焦,需要通过filter配置排除:
less 复制代码
new Sortable(list, {
  filter: '.input', // 过滤掉输入框元素,点击输入框时不触发拖拽
  onFilter: (evt) => {
    // 可选:处理过滤后的逻辑(如聚焦输入框)
    if (evt.item.querySelector('.input')) {
      evt.item.querySelector('.input').focus();
    }
  }
});
  1. 移动端拖拽不生效:确保没有禁止触摸事件,且touch-action样式未被覆盖,可添加:
css 复制代码
.todo-item {
  touch-action: none; /* 允许移动端拖拽 */
}
  1. 大数据列表性能:如果列表项超过 100 个,建议开启scroll配置,优化滚动时的性能:
arduino 复制代码
new Sortable(list, {
  scroll: true, // 拖拽时自动滚动容器
  scrollSpeed: 20, // 滚动速度
  scrollSensitivity: 30 // 距离容器边缘多少像素时开始滚动
});

六、总结

作为前端程序员,高效解决业务需求是核心目标。SortableJS 凭借其轻量、灵活、易用的特点,成为我处理拖拽排序需求的首选工具。从简单的单列表排序,到复杂的多列表看板,再到框架内的无缝集成,它都能胜任。

欢迎jym点赞关注加评论~

相关推荐
言之。6 分钟前
Web技术构建桌面应用-Tauri框架和Electron框架
前端·javascript·electron
萌萌哒草头将军30 分钟前
Node.js v24.7.0 新功能预览 🚀🚀🚀
前端·javascript·node.js
程序员张333 分钟前
Vue3+ElementPlus—高效存储和回显多选项的状态值
javascript·vue.js·前端框架
艾小码38 分钟前
90%前端忽略的3大内存黑洞,这样根治性能飙升300%!
前端·javascript·性能优化
GISer_Jing1 小时前
React Native核心技术深度解析_Trip Footprints
javascript·react native·react.js
Mintopia1 小时前
AIGC 多模态大模型在 Web 场景中的融合技术与挑战
前端·javascript·aigc
Mintopia1 小时前
🛡️ Next.js 中间件权限验证与 API 保护的奇幻冒险
前端·javascript·next.js
叶浩成5201 小时前
Clerk 用户认证系统集成文档
javascript·vue3·clerk
Miracle_G1 小时前
每日一个知识点:几分钟学会页面拖拽分隔布局的实现
前端·javascript
薛定谔的算法1 小时前
深入探索 ES6 中的 Map 数据结构
前端·javascript·算法