Vform3 是一款通过配置json数据,动态生成表单页面的可视化配置页面,方便我们快速的编写表单。
存在的问题:
- 我们在项目的实际开发中发现很多组件,区域内容,组件加载的逻辑是相识和相同的,例如不同的页面之间都存在国家地区组件,前一个表单的数据是又后一个表单生成的等等。
- 作为一名程序员,配置化的方式,有时增加了我们的负担,例如我们需要通过某个按钮去控制列表的展示,我们在配置页面编写点击事件时,无法方便查看到列表对应的ID,此时我们需要点击列表组件才能知道对应的ID,如果能够看到生成后的vue代码,我们就能够方便的找到ID。
无法满足:
Vform3官方目前提供的只有导入,导出整个表单的功能。
Vform3官方目前生成的SFC也是这个表单的,无法查看到局部代码块。
我们只能这么做:
- 方式一:A表单配置了的组件想要导入到B表单,需要先查看整个A表单的JSON,从中获取我们想要的组件JSON数据,再和B进行合并,重新导入。
- 方式二:A表单和B表单一个个对比复制
我们希望实现类似这样的功能:
- 选择某个组件,我们就能获取对应的配置数据
- 表格、页面、卡片等容器组件能整体复制,并导入到另外一个表单中
- 能够查看到每个组件或容器组件SFC的生成,方便我们编写代码
实现效果图
问题一功能实现:
通过组件层次结构树去实现我们问题一的功能。增加三个按钮去实现导入,预览和复制功能。
具体代码:
修改文件src\components\form-designer\toolbar-panel\index.vue
<el-tree
ref="nodeTree"
:data="nodeTreeData"
node-key="id"
default-expand-all
highlight-current
class="node-tree"
icon-class="el-icon-arrow-right"
@node-click="onNodeTreeClick"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<el-button
type="primary"
size="small"
v-if="containerShow(data)"
@click="importClick(node,data)"
>导入</el-button>
<el-button type="primary" size="small" @click="exportClick(node,data)">预览</el-button>
<el-button type="primary" size="small" @click="onCopy(node,data,$event)">复制</el-button>
</span>
</span>
</template>
</el-tree>
//源码中的方法 注解掉组件不能选择问题
onNodeTreeClick(nodeData, node, nodeEl) {
if (nodeData.selectable !== undefined && !nodeData.selectable) {
// this.$message.info(
// this.i18nt("designer.hint.currentNodeCannotBeSelected")
// );
} else {
const selectedId = nodeData.id;
const foundW = this.findWidgetById(selectedId);
if (!!foundW) {
this.designer.setSelected(foundW);
}
}
},
// 导出方法
exportClick(nodeData, node) {
const foundW = this.findWidgetById(node.id);
this.jsonContent1= JSON.stringify(deepClone(foundW), null, " ")
this.showExportJsonDialogFlag = true
},
//导入方法
importClick(nodeData, node) {
ElMessageBox.prompt("请输入数据", "组件导入", {
confirmButtonText: "确认",
cancelButtonText: "取消"
})
.then(({ value }) => {
//this.designer.widgetList 所有组件的json都配置在这里
//过滤获取到当前点击节点widget数据
let foundW = {};
traverseAllWidgets(this.designer.widgetList, w => {
if (w.id === node.id) {
foundW = w;
}
});
try {
let json = JSON.parse(value);
//重新设置名称,id,key
const nameNew = json.type + this.ramdon5();
json.id = nameNew;
if (json.key) {
json.key = this.ramdon5();
}
if (json.options) {
json.options.name = nameNew;
}
if(json.type==='table-cell'){
//表格单元格导入
foundW.cols.push(json);
}else if(foundW.type==='table'){
//表格行列导入
foundW.rows.push(json);
}
else{
//容器导入
foundW.widgetList.push(json);
}
} catch (e) {
ElMessage({
type: "fail",
message: `请输入正确的JSON`
});
return;
}
ElMessage({
type: "success",
message: `导出成功`
});
})
.catch(e => {
ElMessage({
type: "info",
message: e
});
});
},
//控制是否显示可导入
containerShow(node) {
const foundW = this.findWidgetById(node.id);
if (foundW) {
if (foundW.category) {
return true
}
if(foundW.cols){
return true
}
}
return false;
},
ramdon5() {
return Math.floor(
(Math.random() + Math.floor(Math.random() * 9 + 1)) * 10 ** (5 - 1)
);
},
//复制JSON数据到剪切板
onCopy(nodeData, node,e) {
const foundW = this.findWidgetById(node.id);
//vform 自带的工具方法
copyToClipboard(
JSON.stringify(foundW),
e,
this.$message,
this.i18nt("designer.hint.copyJsonSuccess"),
this.i18nt("designer.hint.copyJsonFail")
);
}
修改文件\src\utils\util.js
//过滤获取widget的方法
export function traverseAllWidgets(widgetList, handler) {
if (!widgetList) {
return
}
widgetList.map(w => {
handler(w)
if (w.type === 'grid') {
w.cols.map(col => {
handler(col)
traverseAllWidgets(col.widgetList, handler)
})
} else if (w.type === 'table') {
w.rows.map(row => {
handler(row)//额外添加的 为了实现在列中导入组件
row.cols.map(cell => {
handler(cell)
traverseAllWidgets(cell.widgetList, handler)
})
})
} else if (w.type === 'tab') {
w.tabs.map(tab => {
traverseAllWidgets(tab.widgetList, handler)
handler(tab)//额外添加的 为了实现tab中导入组件
})
} else if (w.type === 'sub-form' || w.type === 'grid-sub-form') {
traverseAllWidgets(w.widgetList, handler)
} else if (w.category === 'container') { //自定义容器
traverseAllWidgets(w.widgetList, handler)
}
})
}
问题二功能实现:
待补充