前端可视化-在 moveable 中添加内部元素排序拖拽功能

业务背景

目前产品中需要添加这样一个功能: 在页面侧边栏有两种不同的元素,外层元素和内部元素,页面右侧为画布区域,需要在左侧拖拽外层元素放置入画布,可以进行拖拽,移动,缩放,框选,对齐 等功能,拖拽内部元素需要不放在画布中,而是放入画布已经存在的外层元素中,并且可以在外层元素中进行拖拽上下排序

需求示意图

采用技术

  • 项目采用技术栈 react
  • 由于需要外层元素可以进行拖拽,移动,缩放,框选等功能,这里选用的是 react-moveable,此插件对于移动拖拽来说功能较为齐全好用
  • 由于 moveable 本身不能对其内部元素有拖拽排序的功能,所以这里采用了 react-sortablejs 来开发内部元素放置如外层元素及在外层元素中拖拽上下排序的功能。(后期改用了 sortablejs,原因后序说明)

遇到的问题

  • 在使用过程中发现,moveable 和 react-sortable 的各自的拖拽事件冲突,导致 react-sortable 在 moveable 中不起作用,拖拽不动,无法达到排序效果,即使设置 forceFallback 也不起作用
    • 在查找 GitHub 的 issue 后发现 react-sortable 可能在对原框架封装上还是存在差异,改用原框架 sortableJs ,并将 forceFallback 设置为 true,(强制执行,将不使用原生的 html5 的拖放,可以修改一些拖放中元素的样式等,就可以内部拖拽排序了)
js 复制代码
// 拖动配置
const ops = {
    animation: 200, // 动画延迟
    group: {
    name: "groupName", // 拖拽组名称,用来和侧边栏拖入的元素配对,控制是否可放入
    pull: false,
    },
    scroll: true,
    className: "sortWarp",
    multiDrag: true, // 开启多选
    multiDragKey: "ctrl", // 多选按键
    selectedClass: "sortable-selected", // 选择的类名
    ghostClass: "sortable-ghostClass", // drop placeholder的css类名
    dragClass: "gragClass",
    filter: ".filterClass", // 过滤器,不需要进行拖动的元素
    cancel: ".cancelClass",
    forceFallback: true, // 忽略 HTML5拖拽行为,强制回调进行
    fallbackTolerance: 3,
    fallbackOnBody: false, // 是否将cloned DOM 元素挂到body元素上。
    removeCloneOnHide: false, // Remove the clone element when it is not showing, rather than just hiding it
    selected: true,
    dataIdAttr: "data-id",
    avoidImplicitDeselect: false, // true - if you don't want to deselect items on outside click
};
  • 此时元素内部可以通过 sortable 进行排序,但是会导致拖拽过程中外层元素移动,原因是因为同时触发了外层元素的 moveable 拖拽事件,导致冲突
    • 解决方案
      • 在内部元素做了鼠标监听 ,移入移出内部元素时控制变量改变 moveable 状态,在移动到内部元素时禁用外层元素 moveable 拖拽,达到内部元素排序拖拽目的。移出后再开启。
js 复制代码
<Moveable
    ref={moveableRef}
    key={moveableKey} // 控制moveable key 强制更新
    target={targets}
    origin={false}
    draggable={isContent ? false : true} // 移入内部元素时 禁止外层元素的拖拽事件
/>
  • 此操作可行,但是在过程中发现问题
    • moveable 状态更新滞后,(移入移除改变变量 isContent 控制 moveable 状态,但是没有实时起作用,后给其设置 key 值一起控制,使其状态更新)

    • 在外层元素拖拽或缩放过程中鼠标快速滑动,会触发内部元素禁止事件导致拖拽停止,并且卡顿

      • 解决方案是监听在外层元素拖拽缩放过程中不触发鼠标事件 ,判断是否还是在拖拽或缩放,直到一个动作完成后才能再次触发内部事件,避免重复触发导致的状态不对或卡顿(卡顿发现是因为大量频繁触发鼠标事件导致,所以同样在排序元素内部做了监听,如果非排序状态才会触发事件)
js 复制代码
<Moveable
    ref={moveableRef}
    key={moveableKey} // 控制 moveable key 强制更新
    target={targets}
    origin={false}
    draggable={isContent ? false : true} // 移入内部元素时 禁止外层元素的拖拽事件
    onDragStart={(e) => {
        setIsDrag(true);
    }}
    onDragEnd={(e) => {
        setIsDrag(false);
    }}
/>
js 复制代码
//在内部元素中
// 修改moveable禁用状态变量

const handleChangeMoveableStatus = (e, status, type) => {
    e?.preventDefault();
    e?.stopPropagation();
    if (!isDrag && !isReSize) {
        // 非正在拖拽外层或缩放外层状态
        setisLayerContent(true);
    };
}
  • 解决后经测试不会再次卡顿,并且达成外层拖拽与内部排序不冲突的条件
  • 成功实现外部元素拖拽及内部元素排序的互不影响~

后记

本文是作者对于个人的学习与总结笔记,如果有谬误的地方,欢迎各位提出并指正~

相关推荐
可涵不会debug2 分钟前
前端基础技术全解析:从HTML前端基础标签语言开始,逐步深入CSS样式修饰、JavaScript脚本控制、Ajax异步通信以及WebSocket持久通信
前端·javascript·css·ajax·html
莫离老师来啦8 分钟前
HTML&HTML5革命:构建现代网页的终极指南 - 0. 课程目录设计
前端·html·html5
hswizy1 小时前
flutter web 路由问题
前端·javascript·flutter
我爱学习_zwj4 小时前
深入浅出Node.js-1(node.js入门)
前端·webpack·node.js
IT 前端 张5 小时前
2025 最新前端高频率面试题--Vue篇
前端·javascript·vue.js
喵喵酱仔__5 小时前
vue3探索——使用ref与$parent实现父子组件间通信
前端·javascript·vue.js
_NIXIAKF5 小时前
vue中 输入框输入回车后触发搜索(搜索按钮触发页面刷新问题)
前端·javascript·vue.js
InnovatorX5 小时前
Vue 3 详解
前端·javascript·vue.js
布兰妮甜5 小时前
html + css 顶部滚动通知栏示例
前端·css·html
种麦南山下5 小时前
vue el table 不出滚动条样式显示 is_scrolling-none,如何修改?
前端·javascript·vue.js