Next-Admin爆肝更新!支持可视化拖拽模块

科技趣谈有前端 2024-04-26 20:32:57

hello,大家好,我是徐小夕,之前和大家分享了很多可视化低代码的最佳实践,以及前端工程化的实战项目,今天继续和大家分享一下我开源的比较有价值的项目——Next-Admin,目前已经支持拖拽搭建模块,并且支持:

参考线吸附组件成组和取消成组组件对齐支持多选,键盘多选开箱即用的拖拽搭建方案

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

在线demo:http://next-admin.com

往期精彩模块演示

drag.gif

技术实现

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

image.png

元素多选我采用了 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工具条实现

image.png

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

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 } }

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

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

tt.gif

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

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

多选 & 成组实现

image.png

下面直接上代码:

<Selecto ref={selectoRef} // dragContainer={container.current} selectableTargets={[".wep-area .cube"]} hitRate={0} selectByClick={true} selectFromInside={false} toggleContinueSelect={["shift"]} ratio={0} onDragStart={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; }} onSelect={e => { const { startAdded, startRemoved, isDragStartEnd, } = e; if (isDragStartEnd) { return; } const nextChilds = groupManager.selectSameDepthChilds( e.data.startTargets, startAdded, startRemoved, ); setSelectedTargets(nextChilds.targets()); }} onSelectEnd={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 了, 如果大家感兴趣也可以研究一下。

后期规划

后续会在 Next-Admin 中集成更多最佳实践,也欢迎感兴趣的朋友一起交流讨论。

如果你对 next 开发或者需要开发一套管理系统, 我相信 Next-Admin 会给你开发和学习的灵感。

同时也欢迎和我一起贡献, 让它变得更优秀~

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

演示地址:http://next-admin.com

由于服务器在国外, 所以建议大家git到本地体验~

欢迎star + 反馈~

0 阅读:1

科技趣谈有前端

简介:感谢大家的关注