Arco-Design + Vue3 封装通过JSON数组类型配置表单组件
import {// 表单json配置项 formJson : {type : Array , } , // 表单校验规则 rules : {type : Object , } , // 表单数据 formState : {// ref绑定组件 const tableForm = ref < FormInstance >();} as any);const {/*** 表单过滤,特殊业务场景需要,
·
Arco-Design + Vue3 封装通过JSON数组类型配置表单组件
一、业务场景
在开发过程中频繁会使用到一些表单,封装一个简单的表单组件来处理这些业务逻辑
二、开发环境
Arco-Design + Vite + Vue3
三、挂载全局组件 TableForm
// components/index.ts注册组件
import { App } from 'vue';
// ...其它组件
import TableForm from './table-form/index.vue';
export default {
install(Vue: App) {
// ...其它组件
Vue.component('TableForm', TableForm);
},
};
四、TableForm.vue组件介绍
<template>
<a-row :gutter="gutter">
<a-form
ref="tableForm"
class="table-form"
:model="formModel"
auto-label-width
:rules="rules"
:layout="layout"
:label-align="labelAlign"
>
<a-col
v-for="field in visibleFields"
:key="field.name"
:span="field.span ? field.span : 22"
:data-index="field.index"
>
<a-form-item
v-if="field.name"
:field="field.name"
:label="field.label"
:tooltip="field.tooltip"
:label-col-flex="`${field.labelWidth}px`"
>
<component
:is="field.type"
v-model="formModel[field.name]"
allow-clear
:multiple="field.multiple"
:style="field.style"
:allow-search="field.search"
:placeholder="field.placeholder"
:options="field.options"
:type="field.elType"
:field-names="field.fieldNames"
:disabled="field.disabled"
:checked-value="field.checkedValue"
:unchecked-value="field.uncheckedValue"
:show-time="field.showTime"
:allow-create="field.allowCreate"
:min="field.min"
:max="field.max"
:step="field.step"
:precision="field.precision"
:mode="field.mode"
@change="change"
/>
</a-form-item>
</a-col>
<slot name="custom"></slot>
</a-form>
</a-row>
</template>
<script lang="ts" setup>
import { toRefs, ref, watch, computed, nextTick } from 'vue';
import { FormInstance, ResponsiveValue } from '@arco-design/web-vue';
import type { FieldProps } from '@/types/global';
const props = withDefaults(
defineProps<{
formJson: Array<any>;
rules?: any;
formState: FieldProps;
layout?: 'horizontal' | 'vertical' | 'inline' | undefined;
labelAlign?: 'left' | 'right' | undefined;
gutter?:
| number
| ResponsiveValue
| [number | ResponsiveValue, number | ResponsiveValue];
display?: boolean | void; // 按条件展示/隐藏组件
}>(),
{
layout: 'horizontal',
formJson: () => [],
display: false,
}
);
const emit = defineEmits(['change']);
// ref绑定组件
const tableForm = ref<FormInstance>();
const formModel = ref({} as any);
const { formJson, rules, formState, layout, labelAlign, gutter } =
toRefs(props);
defineExpose({
formModel,
tableForm,
});
/*
** 表单过滤,特殊业务场景需要,没有则可以删除
** 用于条件判断是否通过表单条件展示需要的内容
*/
const visibleFields = computed(() => {
if (!props.display) {
return formJson?.value === undefined ? false : formJson.value;
}
return props?.display();
}) as unknown as Array<FieldProps>;
/*
* 按 data-index 将组件进行排序
**/
nextTick(() => {
const elements = document.querySelectorAll('.table-form .arco-col');
const formBox = document.querySelector('.table-form');
// 将 elements 转换为数组
const elementsArray = Array.from(elements);
// 按照 data-index 进行排序
elementsArray.sort((a, b) => {
const indexA = a.getAttribute('data-index');
const indexB = b.getAttribute('data-index');
return indexA - indexB;
});
elementsArray.forEach((element) => {
// 如果没有data-index则不需要
if (!element.getAttribute('data-index')) return;
// 将元素插入到 DOM 中
formBox?.appendChild(element);
});
});
const change = (val: any) => {
emit('change', val);
};
// 监听表单数据变化赋值
watch(
() => props.formState,
(val) => {
if (!val) return;
formModel.value = val;
},
{ deep: true, immediate: true }
);
</script>
<script lang="ts">
export default {
name: 'TableForm',
};
</script>
<style lang="less" scoped></style>
表单配置项
- allow-clear 是否支持清空
- multiple 选择框是否支持多选
- style a-form-item的样式
- allow-search 选择框是否支持搜索
- placeholder 占位符
- options选择框的选择项
- 表单组件内的type样式
- field-names options选项值配置
…
其它自定义可以依次添加
五、使用场景
<template>
<a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel">
<template #title>{{ title }}</template>
<TableForm
ref="formRef"
:form-json="newFormJson"
:form-state="state.formModel"
:rules="rules"
:display="filterFormJson"
></TableForm>
</a-modal>
</template>
<script setup lang="ts">
import { reactive, toRefs, ref, watch, computed } from 'vue';
import { omit } from 'lodash';
import { cpDetail } from '@/api/settings';
import { jsonToFormData } from '@/utils';
import { FormModelProps } from '../types';
import { adminFormJson } from '../formJson';
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
title: {
type: String,
default: '',
},
type: {
type: String,
default: '',
},
record: {
type: Object,
default: () => ({}),
},
serviceList: {
type: Array,
default: () => [],
},
logList: {
type: Array,
default: () => [],
},
});
const rules = {
real_name: [
{
required: true,
message: `所属人员不能为空!`,
},
],
account: [
{
required: true,
message: `账号不能为空!`,
},
],
pwd: [
{
required: true,
message: `请输入密码!`,
},
{
minLength: 6,
message: `密码不能少于六位!`,
},
],
comfirmpwd: [
{
required: true,
message: `请确认密码!`,
},
{
minLength: 6,
message: `密码不能少于六位!`,
},
],
pid: [
{
required: true,
message: `上级账号不能为空!`,
},
],
status: [
{
required: true,
message: `状态不能为空!`,
},
],
};
const { visible, title, type, record, serviceList, logList } = toRefs(props);
const state = reactive({
formModel: {
level: '1',
} as FormModelProps,
});
const formRef = ref();
// 生成一个新的json,补全选择框的options
const newFormJson = computed(() => {
return adminFormJson.map((item: any) => {
if (item.name === 'service_ids') {
return {
...item,
options: serviceList.value,
};
}
return { ...item };
});
});
const filterFormJson = () => {
return newFormJson.value.filter((item) => {
if (item.name === 'pid') {
return state.formModel.level === '2';
}
return true;
});
};
const emit = defineEmits(['onOk', 'onCancel']);
const handleCancel = async () => {
emit('onCancel', false);
};
const handleOk = async () => {
// 表单校验
const res = await formRef.value.tableForm?.validate();
if (!res) {
state.formModel.service_ids = state.formModel.service_ids.join();
if (state.formModel.level === '1')
state.formModel = omit(state.formModel, ['pid']);
emit('onOk', false, state.formModel);
}
};
const getCpDetail = async (id: string) => {
const { result } = await cpDetail(jsonToFormData({ id }));
state.formModel = result;
state.formModel.service_ids = result.service_list.map((item) => item.service_id);
state.formModel.pid = data.pid === '0' ? '' : data.pid;
};
watch(
() => type,
(val) => {
if (val.value === 'edit') {
getCpDetail(record.value.id);
state.formModel = omit(state.formModel, [
'last_time',
'service_list',
'p_name',
]);
}
},
{ deep: true, immediate: true }
);
</script>
<style scoped lang="less">
.arco-btn {
width: 80px;
}
.arco-col {
text-align: center;
}
</style>
选择否也就是条件判断是否需要显示其它表单组件
下面贴一下formJson.ts
export const adminFormJson = [
{
name: 'real_name',
label: '所属人员',
type: 'a-input',
placeholder: '请输入所属人员名称',
options: [],
},
{
name: 'account',
label: '账号',
type: 'a-input',
placeholder: '请输入账号',
options: [],
},
{
name: 'service_ids',
label: '授权小程序',
type: 'a-select',
multiple: true,
style: `{textAlign: 'left'}`,
placeholder: '请选择授权小程序',
fieldNames: { value: 'id', label: 'service_name' },
options: [],
},
{
name: 'pwd',
label: '密码',
type: 'a-input',
placeholder: '请输入密码',
options: [],
},
{
name: 'comfirmpwd',
label: '确认密码',
type: 'a-input',
placeholder: '请确认密码',
options: [],
},
{
name: 'level',
label: '是否一级账号',
type: 'a-radio-group',
placeholder: '',
elType: 'button',
options: [
{
value: '1',
label: '是',
},
{
value: '2',
label: '否',
},
],
},
{
name: 'pid',
label: '上级账号ID',
type: 'a-select',
placeholder: '请选择上级账号ID',
fieldNames: { value: 'id', label: 'real_name' },
options: [],
},
{
name: 'status',
label: '状态',
type: 'a-select',
placeholder: '请选择账号状态',
options: [
{
value: '1',
label: '正常',
},
{
value: '2',
label: '禁用',
},
],
},
];
更多推荐
已为社区贡献1条内容
所有评论(0)