VForm自定义组件
一、自定义字段组件
1. 创建组件

创建的组件名称和组件内部的name属性需一致,以防组件调用失败。
2、配置组件参数

3、添加自定义属性
1、在/src/components/form-designer/widget-panel/widgetsConfig.js添加属性

2、在/src/components/form-designer/setting-panel/property-editor创建对应的属性编辑器xxx-editor.vue

3、在/src/components/form-designer/setting-panel/propertyRegister.js中注册组件

4、在/src/lang/zh-CN.js添加中英文对照

4、编译、打包及项目集成
1、编译打包
npm run lib

2、在自己项目中创建/src/lib/vform目录

将生成的designer.style.css和designer.umid.js复制到创建的目录下
3、在vite.config.js中配置
optimizeDeps: {
include: ['@/../lib/vform/designer.umd.js'] //此处路径必须跟main.js中import路径完全一致!
},
build: {
/* 其他build生产打包配置省略 */
//...
commonjsOptions: {
include: /node_modules|lib/ //这里记得把lib目录加进来,否则生产打包会报错!!
}
}
4、在main.js中引入
import vForm from '@/lib/vform/designer.umd.js'
import './lib/vform/designer.style.css'
app.use(vForm)
二、自定义树形容器组件
1. 配置组件参数
{
type: "tree",
icon: "tree",
category: "container",
widgetList: [],
options: {
name: "tree42275",
label: "tree",
size: "default",
disabled: false,
hidden: false,
parentChildLinkAble: true,
customClass: [],
dsEnabled: false,
dsName: "",
dataSetName: "",
showCheckBox: true,
filter: true,
defaultExpandAllNode: true,
expandRetractAllNode: true,
selectClearAllNode: true,
expandOnClickNode: true,
nodeEdit: true,
draggable: false,
lazy: false,
treeDataEdit: true,
onCreated: "",
onMounted: "",
onNodeClick: "",
onNodeCheck: "",
onNodeContextmenu: "",
onCheckChange: "",
treeData: [
{
id: 1,
label: "一级 1",
children: [
{
id: 2,
label: "二级 1-1",
children: [
{
id: 3,
label: "三级 1-1-1"
}
]
}
]
},
{
id: 4,
label: "一级 2",
children: [
{
id: 5,
label: "二级 2-1",
children: [
{
id: 6,
label: "三级 2-1-1"
}
]
},
{
id: 7,
label: "二级 2-2",
children: [
{
id: 8,
label: "三级 2-2-1"
}
]
}
]
},
{
id: 9,
label: "一级 3",
children: [
{
id: 10,
label: "二级 3-1",
children: [
{
id: 11,
label: "三级 3-1-1"
}
]
},
{
id: 12,
label: "二级 3-2",
children: [
{
id: '3-2-1',
label: "三级 3-2-1"
}
]
}
]
}
]
}
}
2. 创建树形组件
<template>
<container-wrapper :designer="designer" :widget="widget" :parent-widget="parentWidget" :parent-list="parentList"
:index-of-parent-list="indexOfParentList">
<div :key="widget.id" class="tree-container"
:class="{'selected': selected}" @click.stop="selectWidget(widget)">
<el-input v-if="widget.options.filter" v-model="filterText" placeholder="输入关键字进行过滤"/>
<el-row class="padding5-top-bottom" v-if="widget.options.expandRetractAllNode || widget.options.selectClearAllNode">
<el-col>
<el-button-group>
<el-button v-if="widget.options.expandRetractAllNode" type="primary" plain round @click="expandAll">展开/收缩</el-button>
<el-button v-if="widget.options.selectClearAllNode" type="primary" plain round @click="selectAll">选中/取消选中</el-button>
</el-button-group>
</el-col>
</el-row>
<el-tree
ref="tree"
node-key="id"
:props="defaultProps"
:data="widget.options.treeData"
:show-checkbox="widget.options.showCheckBox"
:default-expand-all="widget.options.defaultExpandAllNode"
:expand-on-click-node="widget.options.expandOnClickNode"
:draggable="widget.options.draggable"
:filter-node-method="filterNode"
@node-click="handleTreeNodeClick"
@check="handleTreeNodeCheck"
@node-contextmenu="handleTreeContextmenu"
@check-change="handleTreeCheckChange"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span v-if="widget.options.nodeEdit">
<el-button size="small" type="primary" link @click.stop="handleAppend(data)">添加</el-button>
<el-button size="small" type="primary" link @click.stop="handleRemove(node, data)">删除</el-button>
</span>
</span>
</template>
</el-tree>
</div>
</container-wrapper>
</template>
<script>
import i18n from "@/utils/i18n";
import containerMixin from "@/components/form-designer/form-widget/container-widget/containerMixin";
import refMixinDesign from "@/components/form-designer/refMixinDesign";
import ContainerWrapper from "@/components/form-designer/form-widget/container-widget/container-wrapper.vue";
import FieldComponents from "@/components/form-designer/form-widget/field-widget";
import {toRaw} from "vue";
import {treeToArray} from "@/utils/util";
export default {
name: "tree-widget",
componentName: 'ContainerWidget',
mixins: [i18n, containerMixin, refMixinDesign],
inject: ['refList'],
components: {
ContainerWrapper,
...FieldComponents,
},
props: {
widget: Object,
parentWidget: Object,
parentList: Array,
indexOfParentList: Number,
designer: Object,
},
data() {
return {
filterText: '',
isExpanded: true,
isChecked: false,
defaultProps: {
children: 'children',
label: 'label'
},
id: 1000
}
},
computed: {
selected() {
return this.widget.id === this.designer.selectedId
},
customClass() {
return this.widget.options.customClass || ''
},
},
watch: {
filterText(val) {
this.$refs.tree.filter(val)
}
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.label.includes(value)
},
expandAll() {
this.isExpanded =!this.isExpanded
const list = treeToArray(toRaw(this.widget.options.treeData));
list.forEach((item, index) => {
this.$refs.tree.store.nodesMap[list[index].id].expanded = this.isExpanded;
})
},
selectAll() {
this.isChecked =!this.isChecked
const list = toRaw(this.widget.options.treeData);
this.$refs.tree.setCheckedNodes(this.isChecked ? list : [])
},
handleRemove(node, data) {
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex((d) => d.id === data.id)
children.splice(index, 1)
this.widget.options.treeData = [...this.widget.options.treeData]
},
handleAppend(data) {
const newChild = { id: this.id++, label: 'testNode', children: [] }
if (!data.children) {
data.children = []
}
data.children.push(newChild)
this.widget.options.treeData = [...this.widget.options.treeData]
}
}
}
</script>
<style lang="scss" scoped>
div.tree-container {
padding: 5px;
border: 1px dashed #336699;
box-sizing: border-box;
}
.tree-container.selected {
outline: 2px solid $--color-primary !important;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>
3. 创建禁止父子节点联动字段组件(其他组件类似)

<template>
<el-form-item :label="i18nt('designer.setting.parentChildLinkAble')">
<el-switch v-model="optionModel.parentChildLinkAble"></el-switch>
</el-form-item>
</template>
<script>
import i18n from "@/utils/i18n";
export default {
name: "parentChildLinkAble-editor",
mixins: [i18n],
props: {
designer: Object,
selectedWidget: Object,
optionModel: Object,
},
}
</script>
<style scoped>
</style>
- 配置中文映射

在src/lang/zh-CN.js中的setting对象中添加 - 添加组件映射

在src/components/form-designer/setting-panel/propertyRegister.js中的COMMON_PROPERTIES添加
5.创建事件属性组件

在src/components/form-designer/setting-panel/property-editor/event-handler目录下创建,组件名称为事件名称-editor
6. 添加事件组件映射

在src/components/form-designer/setting-panel/propertyRegister.js中的EVENT_PROPERTIES中添加。
7. 添加事件处理方法

handleTreeCheckChange(data, checked, indeterminate) {
if (!!this.widget.options.onCheckChange) {
let remoteFn = new Function('data', 'checked', 'indeterminate', this.widget.options.onCheckChange)
remoteFn.call(this, data, checked, indeterminate)
}
}
在src/components/form-designer/form-widget/container-widget/containerMixin.js中添加
8.编译导入js即可
常见问题
- vite项目中添加自定义组件后不显示

删除node_moudles中的.vite目录,重新运行项目。 - 创建字段组件后不显示
字段组件的文件名称必须是字段名+-editor;文件中的name属性必须根文件名一致




363

被折叠的 条评论
为什么被折叠?



