You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义SortableJS拖拽时的Ghost元素(替代默认图标克隆)

自定义SortableJS跨列表拖拽的Ghost元素方法

直接给你两个可行的实现思路,都是基于Sortable的事件钩子来实现:

方法一:完全自定义Ghost并跟随鼠标

核心是利用onStart/onEnd事件,自己创建自定义元素替代默认Ghost,步骤清晰直接:

  1. 提前准备好自定义Ghost元素(初始隐藏),写好你要的样式和内容
  2. 初始化Sortable时,给默认Ghost加个类,用来隐藏它
  3. 拖拽开始时,显示自定义Ghost,绑定鼠标移动事件让它跟着鼠标走
  4. 拖拽结束后,隐藏自定义Ghost并清理事件监听

代码示例

HTML

<ul class="list" id="list1">
  <li>列表1项1</li>
  <li>列表1项2</li>
</ul>
<ul class="list" id="list2">
  <li>列表2项A</li>
  <li>列表2项B</li>
</ul>

<!-- 自定义Ghost,初始隐藏 -->
<div id="customGhost" style="display:none;position:absolute;pointer-events:none;padding:10px;background:#e6f7ff;border:1px solid #91d5ff;border-radius:4px;">
  🚀 正在拖拽自定义元素
</div>

CSS

/* 隐藏默认的Ghost元素 */
.sortable-ghost {
  display: none !important;
}

JS

// 封装初始化Sortable的函数,复用逻辑
const initSortable = (elId) => {
  return new Sortable(document.getElementById(elId), {
    group: 'cross-list',
    ghostClass: 'sortable-ghost',
    onStart(evt) {
      const customGhost = document.getElementById('customGhost');
      // 显示自定义Ghost,根据鼠标位置设置初始偏移(让元素对齐鼠标中心)
      customGhost.style.display = 'block';
      const offsetX = customGhost.offsetWidth / 2;
      const offsetY = customGhost.offsetHeight / 2;
      customGhost.style.left = `${evt.originalEvent.clientX - offsetX}px`;
      customGhost.style.top = `${evt.originalEvent.clientY - offsetY}px`;

      // 绑定鼠标移动事件,实时更新Ghost位置
      const moveHandler = (e) => {
        customGhost.style.left = `${e.clientX - offsetX}px`;
        customGhost.style.top = `${e.clientY - offsetY}px`;
      };
      document.addEventListener('mousemove', moveHandler);
      // 存下事件处理函数,方便结束时解绑
      evt.moveHandler = moveHandler;
    },
    onEnd(evt) {
      const customGhost = document.getElementById('customGhost');
      // 隐藏自定义Ghost,解绑事件
      customGhost.style.display = 'none';
      document.removeEventListener('mousemove', evt.moveHandler);
    }
  });
};

// 初始化两个列表
initSortable('list1');
initSortable('list2');

方法二:动态修改默认Ghost的内容

如果不想自己做鼠标跟随逻辑,也可以直接修改默认Ghost的内容,步骤更简单:

代码示例

new Sortable(document.getElementById('list1'), {
  group: 'cross-list',
  ghostClass: 'sortable-ghost',
  onStart(evt) {
    // 获取默认的Ghost元素(Sortable拖拽时会自动创建原元素的克隆作为Ghost)
    const ghost = document.querySelector('.sortable-ghost');
    // 替换成自定义内容
    ghost.innerHTML = '<div style="color:#1890ff;font-weight:bold;">🔧 自定义拖拽提示</div>';
    // 额外覆盖样式
    ghost.style.background = '#f0f5ff';
    ghost.style.border = '1px dashed #1890ff';
    ghost.style.padding = '8px';
  }
});

// 第二个列表同理初始化
new Sortable(document.getElementById('list2'), {
  group: 'cross-list',
  ghostClass: 'sortable-ghost'
});

这个方法的缺点是Ghost本质还是原元素的克隆,样式可能受原元素影响,需要额外覆盖。

注意事项

  • 自定义Ghost要加pointer-events:none,避免干扰拖拽的鼠标事件
  • 方法一的偏移量要根据自定义元素的尺寸调整,让它对齐鼠标位置
  • 如果需要根据拖拽的原元素动态变化自定义内容,可以通过evt.item获取原元素的信息,再修改Ghost的内容

内容的提问来源于stack exchange,提问作者Riccoh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:07:37