前端可视化-在 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);
    };
}
  • 解决后经测试不会再次卡顿,并且达成外层拖拽与内部排序不冲突的条件
  • 成功实现外部元素拖拽及内部元素排序的互不影响~

后记

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

相关推荐
子兮曰9 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰9 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万9 小时前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝9 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋10 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
龙亘川10 小时前
明月照湾区,智启新赛道:从顶流文旅IP盛会看智慧文旅升级路径
人工智能·智慧城市·开源软件·数据可视化
卡布鲁11 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
龙亘川11 小时前
一网统管AI平台民生业务实践:基于城市数字底座赋能公积金业务服务升级
大数据·安全·智慧城市·开源软件·数据可视化·政务
汉堡大王952712 小时前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大12 小时前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端