Next-Admin最佳实践!支持可视化拖拽模块

开发 前端
拖拽模块我采用了 movable, 并研究了它的大量 API,最终实现了我想要的效果,当然我还设计了一套数据结构,如果大家对可视化搭建感兴趣,也可以扩展成自己的拖拽搭建结构。

模块演示

图片图片

技术实现

拖拽模块我采用了 movable, 并研究了它的大量 API,最终实现了我想要的效果,当然我还设计了一套数据结构,如果大家对可视化搭建感兴趣,也可以扩展成自己的拖拽搭建结构。

图片图片

元素多选我采用了 selecto 模块,成组管理器我采用了 @moveable/helper, 当然在使用这些库的时候也踩了不少坑,好在已经完美解决。

下面分享一个简单的数据结构,以支持我们的元素自由搭建:

const schema = {
    "Button": {
        id: 'wep_001',
        name: 'Button',
        type: 'base', // 基础类型组件
        base: {
            width: 120,
            height: 36,
            transform: 'translate(100px,100px)'
        }
    },
    "Image": {
        id: 'wep_002',
        name: 'Image',
        type: 'base', // 基础类型组件
        base: {
            width: 120,
            height: 120,
            url: '',
            transform: 'translate(300px,160px)'
        }
    }
}

export default schema

工具条实现

图片图片

对于工具条的实现,我做了统一的封装,以便后期可能更低成本的维护和管理:

  • config 工具条配置
  • actions 工具条选项对应的功能方法

接下来看看工具条的配置:

const toolbar = {
    base: [
        {
            key: 'group',
            icon: <GroupOutlined />,
            text: '成组',
        },
        {
            key: 'ungroup',
            icon: <UngroupOutlined />,
            text: '取消成组'
        },
        {
            key: 'left',
            icon: <AlignLeftOutlined />,
            text: '左对齐'
        },
        // ... 其他工具条配置
        {
            key: 'v-space',
            icon: <PicCenterOutlined />,
            text: '垂直分布空间'
        },
        {
            key: 'h-space',
            icon: <PicCenterOutlined style={{transform: 'rotate(-90deg)'}} />,
            text: '水平分布空间'
        },
        
    ]
}

工具条方法封装:

const handleOperate = (key: string) => {
        // ... some function
        // 顶对齐实现
        if(key === 'top') {
            const rect = moveableRef.current!.getRect();
            // console.log(rect)
            const moveables = moveableRef.current!.getMoveables();

            if (moveables.length <= 1) {
                return;
            }
            moveables.forEach(child => {
                child.request<DraggableRequestParam>("draggable", {
                    y: rect.top,
                }, true);
            });

            moveableRef.current?.updateRect();
            return
        }
        // 底对齐
        if(key === 'bottom') {
            const rect = moveableRef.current!.getRect();
            const moveables = moveableRef.current!.getMoveables();
            if (moveables.length <= 1) {
                return;
            }
            moveables.forEach(child => {
                child.request<DraggableRequestParam>("draggable", {
                    y: rect.top + rect.height - (child.props?.target ? (child.props.target as any).offsetHeight : 0),
                }, true);
            });
            moveableRef.current?.updateRect();
            return
        }

        // ... 其他工具条方法
        // 水平分布
        if(key === 'h-space') {
            const groupRect = moveableRef.current!.getRect();
            const moveables = moveableRef.current!.getMoveables();
            let left = groupRect.left;

            if (moveables.length <= 1) {
                return;
            }
            const gap = (groupRect.width - groupRect.children!.reduce((prev, cur) => {
                return prev + cur.width;
            }, 0)) / (moveables.length - 1);

            moveables.sort((a, b) => {
                return a.state.left - b.state.left;
            });
            moveables.forEach(child => {
                const rect = child.getRect();

                child.request<DraggableRequestParam>("draggable", {
                    x: left,
                }, true);

                left += rect.width + gap;
            });

            moveableRef.current?.updateRect();
            return
        }

    }

通过以上的封装方式我们就能轻松扩展自己的工具条啦~

接下来我们看看工具条实现的效果:

图片图片

当然代码我已经提交到 github 上了, 大家感兴趣可以参考研究一下。

开源地址:https://github.com/MrXujiang/next-admin

多选 & 成组实现

图片图片

下面直接上代码:

<Selecto
    ref={selectoRef}
    // dragCnotallow={container.current}
    selectableTargets={[".wep-area .cube"]}
    hitRate={0}
    selectByClick={true}
    selectFromInside={false}
    toggleCnotallow={["shift"]}
    ratio={0}
    notallow={e => {
        const moveable = moveableRef.current!;
        const target = e.inputEvent.target;
        const flatted = deepFlat(targets);

        if (
            target.tagName === "BUTTON"
            || moveable.isMoveableElement(target)
            || flatted.some(t => t === target || t.contains(target))
        ) {
            e.stop();
        }
        e.data.startTargets = targets;
    }}
    notallow={e => {
        const {
            startAdded,
            startRemoved,
            isDragStartEnd,
        } = e;

        if (isDragStartEnd) {
            return;
        }
        const nextChilds = groupManager.selectSameDepthChilds(
            e.data.startTargets,
            startAdded,
            startRemoved,
        );

        setSelectedTargets(nextChilds.targets());
    }}
    notallow={e => {
        const {
            isDragStartEnd,
            isClick,
            added,
            removed,
            inputEvent,
        } = e;
        const moveable = moveableRef.current!;

        if (isDragStartEnd) {
            inputEvent.preventDefault();

            moveable.waitToChangeTarget().then(() => {
                moveable.dragStart(inputEvent);
            });
        }
        let nextChilds: TargetList;

        if (isDragStartEnd || isClick) {
            if (isCommand) {
                nextChilds = groupManager.selectSingleChilds(targets, added, removed);
            } else {
                nextChilds = groupManager.selectCompletedChilds(targets, added, removed, isShift);
            }

        } else {
            nextChilds = groupManager.selectSameDepthChilds(e.data.startTargets, added, removed);
        }
        e.currentTarget.setSelectedTargets(nextChilds.flatten());
        setSelectedTargets(nextChilds.targets());
    }}
></Selecto>

完整代码都同步到 Next-Admin 了, 如果大家感兴趣也可以研究一下。

责任编辑:武晓燕 来源: 趣谈前端
相关推荐

2020-07-22 10:30:54

数据可视化分析平台分析工具

2020-12-22 14:14:25

大数据数据可视化

2015-09-21 09:21:07

2015-10-28 13:28:57

2020-03-11 14:39:26

数据可视化地图可视化地理信息

2024-03-06 19:57:56

探索商家可视化

2017-10-14 13:54:26

数据可视化数据信息可视化

2022-08-26 09:15:58

Python可视化plotly

2009-04-21 14:26:41

可视化监控IT管理摩卡

2023-03-09 15:11:30

数据可视化工具matplotlib

2024-07-25 14:04:16

2023-11-30 09:34:14

数据可视化探索

2024-06-06 08:27:42

2017-10-25 13:04:10

数据可视化信息可视化数据图表

2020-03-07 21:48:46

物联网可视化技术设计

2018-07-11 12:30:51

编程语言Python数据可视化

2015-08-20 10:06:36

可视化

2020-12-04 17:15:17

数据可视化node.js

2022-01-14 07:56:38

流布局设计拖拽
点赞
收藏

51CTO技术栈公众号