vben-admin(2.8.0)中basicForm的使用(包含basicTable中开启searchForm中的使用)

分享一下最近使用vben-admin中basicForm的一些心得吧(鱼都摸秃了

首先确认一下您使用vben是2.8.0版本的而不是vben3(我也在学习中),其中有些不足之处也请各位大佬多多包涵,欢迎各位大佬在评论区留言指正,我也会不断学习。同时本文也会在各位大佬的指正之下不断修改。

首先是BasicForm的使用:

先看看文档的基本使用: 其中一些参数的介绍和一些表单的配置在文档中都有介绍,这里就不过多赘述了,不懂小伙伴仔细阅读一些文档,实在找不到配置的可以评论区向各位大佬请教,我能回答的也一定会去回复的。

先说一下我遇到的最多的吧,就是表单中select的数据问题,因为后端没有把返回数据统一起来label、key、value啥的都会给你,我这边最多的就是对返回数据的处理

js 复制代码
        // 这是基础的一个select
        {
            field: 'state',
            label: '状态',
            component: 'Select',
            colProps: {
              span: 12,
            },
            componentProps: {
              options: [
                {
                  label: '排队中',
                  value: 'IN_LINE',
                },
                {
                  label: '已退出',
                  value: 'HAS_EXITED',
                },
                {
                  label: '已办证',
                  value: 'HAS_CERTIFIED',
                },
                {
                  label: '待审核',
                  value: 'WAIT_REVIEWED',
                },
                {
                  label: '已驳回',
                  value: 'HAS_REJECTED',
                },
              ],
            },
            required: true,
          },

这是一个简单的Select所有选项都是由前端定死的

但是如果数据是后端给的并且数据并不是这种 [{ label:<String>, value:<String> }]形式的,我们也可以通过ApiSelect的形式去获取动态数据

js 复制代码
{
    label: '角色',
    colProps: {
      span: 8,
    },
    field: 'roleId',
    component: 'ApiSelect',
    componentProps: {
      api: (params) => Api.getRulesList({ params }),
      getPopupContainer: () => document.body,
      labelField: 'name',
      valueField: 'id',
      immediate: false,
      placeholder: '请选择角色',
    },
  },

api: (params) => Api.getRulesList({ params })是我用了axiosClient封装了一下,感兴趣的可以去npm上看一下这个,最终给我的就是接口返回的数组了

但是后端大佬又给我出难题了,给了[<string>,<string>,<string>......]这种格式的,怎么办呢?

喽一眼文档:

我悟了

js 复制代码
{
            field: 'city',
            component: 'ApiSelect',
            label: '城市',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_cityList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择城市',
                immediate: true,
              };
            },
            colProps: {
              span: 12,
            },
          },

ok,那么这个问题解决之后,又来难题了(联动)那怎么搞?再去看看文档

嗯~不错,上手

js 复制代码
  {
            field: 'city',
            component: 'ApiSelect',
            label: '城市',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_cityList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择城市',
                immediate: true,
                onChange: (e) => {
                  countyParams.value.city = e;
                  formModel.county = null;
                  formModel.street = null;
                  formModel.gridName = null;
                },
              };
            },
            colProps: {
              span: 12,
            },
          },
          {
            field: 'county',
            component: 'ApiSelect',
            label: '区县',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_countyList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择区县',
                params: countyParams.value,
                onChange: (e) => {
                  countyParams.value.county = e;
                  formModel.street = null;
                  formModel.gridName = null;
                },
                immediate: true,
              };
            },

            colProps: {
              span: 12,
            },
          },
          {
            field: 'street',
            component: 'ApiSelect',
            label: '街道',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_streetList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择街道',
                params: countyParams.value,
                onChange: (e) => {
                  countyParams.value.street = e;
                  formModel.gridName = null;
                },
                immediate: true,
              };
            },

            colProps: {
              span: 12,
            },
          },

这里注意:params变化是基于watch来完成的,所以你要确保它能侦听到你数据的变化

其实到这里我就有点不明白了,这一个又一个选择框的干嘛不用级联呢?问了下产品,产品:"客户想要这样的"(我内心os:你*** 的 *** ** )

然后我们看下插槽的使用

js 复制代码
  {
    label: '组织',
    colProps: {
      span: 12,
    },
    field: 'organIds',
    component: 'Select',
    slot: 'organTree',
  },
html 复制代码
<template>
  <BasicModal
    v-bind="$attrs"
    @register="registerModal"
    :title="getTitle"
    width="600px"
    @ok="handleSubmit"
  >
    <BasicForm @register="registerForm">
      <template #organTree="{ model, field }">
        <TreeSelect
          v-model:value="model[field]"
          show-search
          treeCheckable
          :show-checked-strategy="SHOW_PARENT"
          style="width: 100%"
          :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
          placeholder="请选择组织"
          allow-clear
          tree-default-expand-all
          :tree-data="treeData"
          :field-names="{
            children: 'children',
            label: 'abbrName',
            value: 'id',
          }"
        />
      </template>
    </BasicForm>
  </BasicModal>
</template>

然后就是校验

js 复制代码
 {
    label: '手机',
    field: 'mobile',
    component: 'Input',
    // required: true,
    colProps: {
      span: 12,
    },
    rules: [
      {
        required: false,
        message: '请输入用户手机号',
      }, 
      {
        validator: async (_, value) => {
          if (!value) {
            return Promise.resolve();
          } else {
            const role = /^((1[3,4,5,6,8,7,9][0-9])|(14[5,7])|(17[0,6,7,8])|(19[7]))\d{8}$/;
            const regular = new RegExp(role);

            if (regular.test(value)) {
              return Promise.resolve();
            } else {
              return Promise.reject('手机号格式不正确');
            }
          }
        },
      },
    ],
  },

然后碰到了一个问题,就是这些规则是写死的还好,但是我的校验如果是动态可以配置的,那么怎么办呢?

js 复制代码
 {
    label: '密码',
    field: 'password',
    component: 'StrengthMeter',
    componentProps: ({ formModel }) => {
      return {
        placeholder: '请输入密码',
        onChange: (e) => {
          formModel.password = e;
        },
      };
    },
    colProps: {
      span: 12,
    },
    rules: [
      {
        validator: async (value) => {
          const userStore = useUserStore();
          // arr是我从登录的时候获取的一个数组里面是各种校验规则,比如必须包含特殊字符,密码长度,必须包含英文大小等等
          const arr = userStore.regularStr;
          if (!value) {
            return Promise.resolve();
          } else {
            let a: any = [];
            // 获取校验不成功的项
            a = arr.filter((i) => {
              return !i.str.test(value);
            });
            // 如果没有就抛出成功
            if (a.length == 0) {
              return Promise.resolve();
            }
            // 如果有就抛出首项
            for (let i = 0; i < a.length; i++) {
              return Promise.reject(a[i].warning);
            }
          }
        },
        // ❗❗❗ change 校验慢一步 blur 客户体验感不太好
        trigger: 'blur',
      },
    ],
  },

这样就解决了校验规则可配的问题,但是如果是chage的话就会发现value始终获取的是上一次输入的值,确定了不是async的问题,请各位大佬指教。

然后就是在BasicTable中开启searchForm后form的使用

首先,基本的一些配置是和form差不多的,只是要使用form的方法需要额外做一下引用

然后就是插槽的使用,与BasicForm中的插槽不同的是,在BasicTable中开启searchForm之后要使用表单的插槽的话就需要额外加上"form-"

话不多说上图

当然这只是这种使用插槽的方式,你也可以使用别的方式来用。

重点来了,上文介绍的那种省市县联动的形式,我们已经解决了,但是呢产品那边又来活了,产品:你能加上默认值吗? 我:可以,加时间!产品:要多久?我:一周吧!🤫

首先明确一下需求,这个默认值是用于table的表头搜索的,并且之间有联动;那么 ------ 开工......

js 复制代码
<template>
  <TitleCard>  </TitleCard>
  <Card>
    <BasicForm @register="register" />
  </Card>
 
</template>

<script setup lang="ts">
  import { ref } from 'vue';
  import { Card } from 'ant-design-vue';
  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
  import TitleCard from '../components/TitleCard/index.vue'; 
  import Api from '../api';
  const formDate: any = ref({});
  const schemas: FormSchema[] = [
    {
      field: 'year',
      component: 'Select',
      label: '年份',
      colProps: {
        span: 6,
      },
    },
    {
      field: 'month',
      component: 'Select',
      label: '月份',
      colProps: {
        span: 6,
      },
    },
  ];

  const getHeardList = async () => {
    const yearsList = await Api.market_monitor_years();
    updateSchema({
      label: '年份',
      colProps: { xl: 6 },
      field: 'year',
      component: 'Select',
      componentProps: ({ formModel }) => {
        return {
          getPopupContainer: () => document.body,
          onChange: async (e) => {
            if (formModel.month) {
              formModel.month = null;
            }
            if (e) {
              const monthOptions = await Api.common_getAllMonth({ params: { year: e } });
              // getMonthParams.value.year = e;
              updateSchema({
                label: '月份',
                colProps: {
                  span: 6,
                },
                field: 'month',
                component: 'Select',
                componentProps: ({ formModel }) => {
                  return {
                    getPopupContainer: () => document.body,
                    onChange: async (e) => {
                      if (e) {
                        formModel.month = e;
                        formDate.value = getFieldsValue();
                      }
                    },
                    options: monthOptions.map((i) => {
                      return {
                        label: i.key + '月',
                        value: i.value,
                      };
                    }),
                  };
                },
              });
              if (monthOptions.length != 0) {
                setFieldsValue({ month: monthOptions[0].value });
              }
            }
          },
          options: yearsList.map((i) => {
            return {
              label: i.key,
              value: i.value,
            };
          }),
        };
      },
    });
    setFieldsValue({
      year: yearsList[0].value,
    });
  };
  getHeardList();

  const [register, { updateSchema, setFieldsValue, getFieldsValue }] = useForm({
    labelWidth: 100,
    schemas,
    actionColOptions: {
      span: 24,
    },
    showActionButtonGroup: false,
  });
</script> 

因为要设置默认值,又要联动,所以写出来的东西一层又一层的看起来很繁琐,有没有更好的方式来写,请各位大佬指正。

还有就是表格单元格开启编辑 这个编辑就不能在schmes里面配置了,需要在BasicTable的columns里面进行配置

js 复制代码
    // 正常的columns
    {
      title: '代码',
      dataIndex: 'regularCode',
      key: 'regularCode',
      width: 100,
    },
js 复制代码
   {
      title: '方式',
      dataIndex: 'methodRevised',
      key: 'methodRevised',
      // width: 160,
      edit: true,
      editComponent: 'ApiSelect',

      editComponentProps: ({}) => {
        return {
          // 正常这样配置就会拿着当前行的id去请求下拉框数据
          // api: () => Api.getDeliveryOptionType({ pathVars: { id: record.id } }),
          // 因为后面业务变更,所以我这边需要拿着表头筛选框的数据来请求数据
          api: async () => {
            const formModel = getForm().getFieldsValue();
            if (!formModel.year || !formModel.month || !formModel.freq) {
              return;
            }
            let list = await Api.getDeliveryOptionType({ params: { ...formModel } });
            return Promise.resolve(list);
          },
          getPopupContainer: () => document.body,
          labelField: 'value',
          valueField: 'key',
        };
      },
    },

表单提交在他们示例里面已经有很详细的代码演示了,这里就不再多说了

欢迎JYM评论指正

相关推荐
y先森2 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy2 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189112 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿3 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡4 小时前
commitlint校验git提交信息
前端
虾球xz4 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇5 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒5 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员5 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐5 小时前
前端图像处理(一)
前端