赞
踩
前面我写过一个自定义电子签名的formcreate表单设计器组件,那时初识formcreate各种使用也颇为生疏,不过总算套出了一个组件不是。此次时隔半年又有机会接触formcreate,重新熟悉和领悟了一番各个方法和使用指南。趁热打铁将此次心得再次分享。
本次要实现的自定义组件是一个表格,表格在前端是个十分常见的组件,然而formcreate里面却没有内置,我翻了issues里面有大佬说可以直接用VxeTable来做,做不做内置都是一样的。于是沿着这个思路自己做了一番实践最终也实现了两个版本,一个是Element Table简易版,一个是VxeTable的高度定制。下面就具体说说实现方法,以及其中遇到的一些问题和解法。
只要前端可以手动输入列名的label和value,我们就可以根据这串json,遍历实现一个表格。实现代码的代码如下:
<el-table
:data="tableOptions.tableData"
:border="tableOptions.showBorder"
:show-summary="tableOptions.showSummary"
:summary-method="getSummaries"
size="mini"
style="width: fit-content"
>
<!--多选列-->
<el-table-column
v-if="tableOptions.showMultiSelect"
type="selection"
width="50"
align="center"
/>
<!--序号列-->
<el-table-column
v-if="tableOptions.showIndex"
type="index"
label="序号"
width="50"
align="center"
/>
<!--数据列-->
<el-table-column
v-for="column in tableOptions.tableColumns"
:key="column.value"
:label="column.label"
:prop="column.value"
width="120"
align="center"
>
<template slot-scope="scope">
<span v-if="tableOptions.readonly">
{{ scope.row[column.value] }}
</span>
<el-input
v-else
v-model="scope.row[column.value]"
:value="scope.row[column.value]"
/>
</template>
</el-table-column>
</el-table>
<el-button
v-if="!tableOptions.readonly"
type="text"
icon="el-icon-plus"
@click="addRow"
>
添加一行
</el-button>
组件生产规则在上一篇文章中已经说过了,不熟悉的同学可以去回顾下。Vue——formcreate表单设计器自定义组件实现
这里简略说一下本次开发中新得到的一些体验和实验方法吧。
import SignBoard from "../components/esign/SignBoard.vue";
export const signboard = {
rule() {
return {
component: SignBoard, //挂载自定义组件
};
},
}
这种方法相对繁琐一点,本次在git上面查询问题时,偶然看到一句话说,只要是全局引入到自定义组件都可以直接在表单设计器中直接使用
,就像你使用iView
,ElementUI
一样方便,经测试确实可行,一起来看代码;
1、main.js 全局引入表格组件
import FormTable from "@/views/process/components/table/FormTable.vue";
Vue.component("FormTable", FormTable)
2、tableRule.js 组件生产规则文件中使用
export const formTable = {
rule() {
return {
//生成组件的名称
type: "FormTable",
//field formcreate生成的json文件中用了收集组件填充数据的字段名称
field: "tableValue",
};
},
}
自定义属性也定义在组件生成规则js文件中,写在prop()
中。
export const formTable = {
//拖拽组件配置项(props)的生成规则
props() {
return [
//生成`checkbox`组件的`options`配置规则
FcDesigner.makeOptionsRule("options"),
{ type: "switch", field: "showSummary", title: "是否显示表尾合计" },
];
}
};
有一些公共默认属性,通常是标签宽度,标签位置,表单尺寸
等。如果我们需要一些自定义属性需要自己在组件规则文件的props() 中添加一个对象,type可以是输入框,开关,计数器,单选,下拉框
等基本控件,可以是TableOptions,Struct
高级输入等。
基础控件使用参考:http://www.form-create.com/v2/element-ui/
高级控件使用参考:https://gitee.com/xaboy/form-create-designer/tree/master/src/components
当你不知道你所使用的控件怎么在组件规则里面使用时,可以找官方提供的组件源码来看下,参观里面的配置即可。
官方组件生成规则参考:https://gitee.com/xaboy/form-create-designer/tree/master/src/config/rule
如上图,Table中增加了设置表头列名,是否显示表格边框,表尾合计(且支持自定义合计列),显示序列号,显示多选列,初始表格行数等属性,其中开关按钮,计数器组件等都比较简单,可以设置默认值,控制属性等,直接参考官方代码就好。我会详细说明下Struct
,Button
,TableOption
,多选下拉框
等实现过程。
Struct是一个点击按钮,弹出一个dialog,可以自由编写输入一串json的一个组件。效果如下:
这样我们自定义属性处理的内容就可以非常灵活了,比如我们希望根据一串json配置自动生成一个自定义表格,这个下一节展开说。或者说我们可以定义表格初始化显示的数据等等;
{
type: 'Struct',
field: 'headers',
title: '设置上传的请求头部',
props: {
defaultValue: {}
}
}
上面的Struct组件是点击一个按钮弹出一个dialog,有的同学可能说,我不想点击按钮弹出dialog,我想做其他自定义操作可以吗?当然可以啦~只不过官方并没有给出button的使用说明,经过研究和实践,我们需要使用原生el-button同时为button绑定click事件
就能进行自定义操作了。
官方源码参考:https://gitee.com/xaboy/form-create-designer/blob/master/src/config/base/field.js
这里我们来实现一个点击按钮给表格新增一行的小功能。实现思路为:
点击按钮更新表格行数,这里我们需要先获取表格原本的行数,然后给其+1;
自定义组件中监听表格行数属性的变化,然后重新绘制表格行数;
根据这个思路一起来看下这个代码如何实现:
1、给按钮设置点击事件并更新表格行数
{ type: "hidden", field: "rowNums", value: 1 },
{
type: "el-button",
props: {
type: "primary",
size: "mini",
icon: "el-icon-delete"
},
inject: true,
on: {
click({ $f }) {
//更新组件规则,否则数据修改不会更新UI
let rowNums = $f.getRule("rowNums").value
$f.updateRule("rowNums", {
value: rowNums+1,
});
const rule = $f.rule;
if (rule) {
rule.addRow = true;
$f.updateRule(rule);
}
}
},
native: true,
children: ["新增一行"]
},
这里有一些知识点需要说明下:
1、如何获取表格的行数?
这里我们通过一个隐藏字段来收集表格的行数;
2、如何更新表格的行数?
首先我们需要获取表格行数的属性,并将其更新。注意此处只修改属性值是没用的,我们需要将这个规则进行刷新,否则不会更新Ui。
组件规则的操作可参考:更新指定规则
3、$f
是什么?
这里参考下官方文档的解释:获取$f,他应该代表的就是FCDesigner对象,有兴趣的同学可以打印看下他的结构。
2、根据表格行数更新Ui
修改完表格行数后,我们需要在UI组件中监听这个数值的变化并根据这个数值更新UI。
props: {
formCreateInject: {
type: Object,
required: true
}
},
watch: {
//formCreateInject为组件生成时会给自定义组件注入的参数
"formCreateInject.rule.props": {
handler() {
//当表单设计器的自定义设置规则修改时,同步更新FormCreateDesiger中的自定义组件
this.update();
},
deep: true
},
},
update(){
let rowNums = this.formCreateInject.rule.props?.rowNums ?? 1;
for (let i = 0; i < rowNums - this.tableOptions.tableData.length; i++) {
this.tableOptions.tableData.push({});
}
}
实现过程比较简单,其中有一点解释下,我们注意下这个formCreateInject
这个对象为表单设计器生成自定义组件时自动注入的参数,这个属性需在UI组件的自定义属性中定义,否则没法实现组件数据的回传等等;
官方说明:预定义 props
TableOption,根据名字就可以知道它是一个表格相关组件,如下图:
点击添加按钮可以新增一行,在Table组件中就是用这个组件来实现自定义列名和表头的。
官网源码参考:https://gitee.com/xaboy/form-create-designer/blob/master/src/utils/index.js
{
type: "TableOptions",
field: "columns",
title: "设置表头和列名",
props: {
defaultValue: []
},
},
输入完成后我们将得到如下json:
[
{
label: 'seq',
value: ‘’
},
], //数据列
然后根据这个数据实现Ui组件中的列的绘制。
这一节将介绍如何实现自定义行尾合计列的实现方式。
首先需添加一个下拉框来实现自定义列的选择;
其次需要将已选的列回传给Table组件,这里就用到了组件属性之间的联动,
可参考官方文档:组件联动概括来说就是,我们可以在某个组件规则的前后,甚至子级增加对另外一个组件规则的控制;在本例中,我们需要用TableOption控制表尾合计列多选拉下框的显示
;所以合起来的代码应该为{
type: "TableOptions",
field: "columns",
title: "设置表头和列名",
props: {
defaultValue: []
},
//组件联动:设置完列名以后,更新显示合计列的多选下拉列表
control: [
{
handle(val, fApi) {
sumColums = val;
sumColumsVal = [];
if (sumColums?.length > 0) {
sumColums.forEach(item => {
sumColumsVal.push(item.value);
});
}
//更新组件规则,否则数据修改不会更新UI
fApi.updateRule("sumColumns", {
value: sumColumsVal,
options: sumColums
});
return val?.length > 0;
},
append: "showSummary", //在某个组件后插入
rule: [
{
type: "select",
field: "sumColumns",
title: "自定义表尾合计列",
value: sumColumsVal,//选择的数据,类型为【】
options: sumColums,//选项数据
props: {
multiple: true
}
}
]
}
]
},
{ type: "switch", field: "showSummary", title: "是否显示表尾合计" },
Ui组件中只计算某些列的合计实现如下:
//自定义合计方法,可以选择只计算某些列的合计,不需要计算的返回空
getSummaries(param) {
//需要计算合计的列
let sumColumns = this.formCreateInject.rule.props?.sumColumns;
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "合计";
return;
}
let values = [];
if (sumColumns?.length > 0) {
//只计算选中列的合计
values = data.map(item => {
return sumColumns.indexOf(column.property) != -1
? Number(item[column.property])
: "-";
});
} else {
//默认计算所有列的合计
values = data.map(item => Number(item[column.property]));
}
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
} else {
sums[index] = "";
}
});
return sums;
}
前面一节自己实现表格只能是比较简单的样式和效果,如果我想要更复杂的表格呢?如果只是增加更多的自定义属性来控制表格的实现,那么必定增加运营配置人员的负担。此时VxeTable就为我们提供一个强大的功能,只要写好高级配置的json,代码中就可以根据这个json直接生成效果更为丰富的表格。
VxeTable官方文档参考:https://vxetable.cn/#/table/start/install
本节我们用到的是VxeTable高级表格的能力,大概预览下高级表格的实现代码:
<template>
<div>
<vxe-grid v-bind="gridOptions"/>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { VxeGridProps } from 'vxe-table'
interface RowVO {
id: number
name: string
nickname: string
role: string
sex: string
age: number
address: string
}
const gridOptions = reactive<VxeGridProps<RowVO>>({
border: true,
height: 300,
align: null,
columnConfig: {
resizable: true
},
columns: [
{ type: 'seq', width: 50 },
{ field: 'name', title: 'name' },
{ field: 'sex', title: 'sex' },
{ field: 'address', title: 'Address' }
],
toolbarConfig: {
slots: {
buttons: 'toolbar_buttons'
}
},
data: [
{ id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
{ id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
{ id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' }
]
})
</script>
由上述代码可见,Vxetable的代码非常简洁,只需要一个option配置项就可以来,那么沿着这个思路,我们就可以把option放在自定义属性中用Struct来进行编辑,就能快速实现不同效果的表格,这个方法对配置人员对要求较高T=T
实现过程不难,代码就不放了。有兴趣的同学可以自行实践。
本篇文章介绍的内容较多,相信经过这篇介绍,以后再有自定义组件的需求时你一定都能游刃有余了。也有些盲点可能没扫到,后续有研究会继续更新的。有好的思路也欢迎评论区留言探讨~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。