第三篇:拖拽功能与布局系统
前两篇我们分析了低代码平台表单设计系统的整体架构和组件体系,这一篇将深入探讨拖拽功能与布局系统的实现
1. 拖拽功能实现
该低代码平台使用 vuedraggable 库实现组件的拖拽功能,主要包括两个场景:
1.1 从左侧组件库拖拽到画布
ini
<draggable
:list="formDefine"
:group="{ name: 'widget', pull: pullFuction, put: false }"
item-key="id"
:sort="false"
@start="dragStart"
>
<template #item="{ element }">
<div class="item" @click="addComponent(element)" fill="currentColor">
<span v-html="icons[element.type]" class="item-icon"></span>
<span>{{ element.title }}</span>
</div>
</template>
</draggable>
核心实现:
- 使用 vuedraggable 组件包装左侧组件列表
- 配置 group 属性,设置拖拽组名为 "widget"
- pull 函数控制拖拽行为,支持克隆模式
- dragStart 事件处理拖拽开始时的逻辑
- addComponent 方法处理点击添加组件的逻辑
1.2 画布内组件的拖拽排序
ini
<draggable
:list="props.formData.list"
group="widget"
item-key="id"
@add="handleAdd"
>
<template #item="{ element }">
<FormDesignView
@on-widget-select="widgetSelect(element)"
:item="element"
:chosenItem="currentItem"
:formData="formData"
></FormDesignView>
</template>
</draggable>
核心实现:
- 使用 vuedraggable 包装画布内的组件列表
- 配置 group 属性为 "widget",与左侧组件库保持一致
- @add 事件处理组件添加到画布的逻辑
- item-key 使用组件的 id 确保正确的DOM更新
1.3 拖拽逻辑处理
scss
// 拖拽开始处理
const dragStart = (e) => {
currentDragItem.value = formDefine[e.oldDraggableIndex]
const currentType = currentDragItem.value.type
currentTemplate(currentType)
triggerScroll()
}
// 处理添加组件
const handleAdd = ({ newIndex }) => {
const itemId = props.formData.list[newIndex].type + '_' + new Date().getTime()
props.formData.list[newIndex] = {
...JSON.parse(JSON.stringify(props.formData.list[newIndex])),
itemId,
grid: props.formData.config?.colSpan || 24
}
currentItem.value = props.formData.list[newIndex]
}
拖拽处理特点:
- 拖拽时克隆组件,而非移动原始组件
- 为新添加的组件生成唯一的 id
- 应用当前表单的布局配置
- 自动选中新添加的组件
- 触发右侧配置面板的更新
2. 布局系统设计
2.1 布局配置选项
表单布局通过 FormConfig 组件进行配置,支持多种布局方式:
ini
<el-form-item label="表单布局" :label-position="itemLabelPosition">
<el-select v-model="config.colSpan">
<el-option
v-for="item in layOutOptions"
:key="item.key"
:label="item.name"
:value="item.colSpan"
/>
</el-select>
</el-form-item>
布局选项:
vbnet
const layOutOptions = [
{
key: 'single',
name: '单列',
colSpan: 24
},
{
key: 'double',
name: '双列',
colSpan: 12
},
{
....省略
}
]
2.2 标签对齐方式
支持三种标签对齐方式:
ini
<el-form-item label="标签对齐方式" :label-position="itemLabelPosition">
<el-radio-group
v-model="config.labelPosition"
aria-label="label position"
@change="handleLabelPositionChange"
>
<el-radio-button value="left">左侧</el-radio-button>
<el-radio-button value="right">右侧</el-radio-button>
<el-radio-button value="top">顶部</el-radio-button>
</el-radio-group>
</el-form-item>
2.3 标签宽度配置
ini
<el-form-item label="标签宽度" :label-position="itemLabelPosition">
<el-input-number
v-model="config.labelWidth"
:min="60"
:max="500"
>
<template #suffix>
<span>px</span>
</template>
</el-input-number>
</el-form-item>
2.4 组件级布局控制
每个组件可以单独设置宽度:
ini
<el-form-item label="字段宽度" v-if="specialShow">
<el-radio-group v-model="item.grid" class="field-width-wrapper">
<el-radio-button :value="6" label="1/4" />
<-- 省略-->
<el-radio-button :value="24" label="整行" />
</el-radio-group>
</el-form-item>
3. 布局渲染实现
3.1 响应式布局
使用 Element Plus 的栅格系统实现响应式布局:
xml
<el-col :span="fixGridOptions.includes(item.type) ? 24 : finalGrid">
<!-- 组件内容 -->
</el-col>
布局计算逻辑:
scss
const { finalGrid, fixGridOptions } = useFormData()
// 监听组件属性和表单属性的布局变化
watch(
() => props.formData.config?.colSpan,
(newVal) => {
finalGrid.value = newVal
props.item.grid = newVal
}
)
3.2 固定宽度组件
某些组件(如多标签页、分割线等)需要固定宽度:
arduino
const fixGridOptions = [
FORM_TYPE.MULTI_TAB,
FORM_TYPE.SEPARATOR,
// 其他需要固定宽度的组件
]
4. 拖拽与布局的交互
4.1 拖拽时的布局应用
当组件被拖拽到画布时,会自动应用当前表单的布局设置:
javascript
const handleAdd = ({ newIndex }) => {
// ...
props.formData.list[newIndex] = {
...JSON.parse(JSON.stringify(props.formData.list[newIndex])),
itemId,
// 应用当前表单配置的布局
grid: props.formData.config?.colSpan || 24
}
// ...
}
4.2 布局变更的实时响应
当表单布局发生变化时,所有组件会自动更新:
ini
watch(
() => props.formData.config?.colSpan,
(newVal) => {
finalGrid.value = newVal
props.item.grid = newVal
}
)
4.3 组件宽度的独立控制
组件可以覆盖表单的默认布局,设置自己的宽度:
javascript
watch(
() => props.item.grid,
(newVal) => {
finalGrid.value = newVal
}
)
5. 技术亮点
- 流畅的拖拽体验 :使用 vuedraggable 实现平滑的拖拽效果
- 智能的布局应用 :拖拽时自动应用表单布局设置
- 灵活的布局选项 :支持多种布局方式和标签对齐方式
- 组件级布局控制 :每个组件可以单独设置宽度
- 响应式设计 :基于 Element Plus 的栅格系统
- 实时布局更新 :布局变更实时反映到所有组件
- 固定宽度组件 :某些组件自动使用固定宽度
这种拖拽与布局系统的设计,大大简化了表单设计过程。用户可以通过直观的拖拽操作和灵活的布局配置,快速创建出表单。并且还有预览功能,直接在预览界面就可实时看到表单布局和试用数据填报。
下一篇预告 :《组件属性配置系统》,将详细分析组件属性配置的实现机制和设计思路。