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

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

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

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

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

往期精彩

模块演示

drag.gif

技术实现

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

image.png

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
js复制代码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 工具条选项对应的功能方法

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
js复制代码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: '水平分布空间'
},

]
}

工具条方法封装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
js复制代码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

下面直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
js复制代码<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 + 反馈~

更多推荐

可视化表单&试卷搭建平台技术详解

爆肝1000小时, Dooring零代码搭建平台3.5正式上线

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%