基于Ant-Design-Vue设计的配置化表单

news2024/11/14 11:22:11

适用vue 3.4 版本以上

在日常的前端开发中,表单开发必不可少,尤其是在遇到一些大型的复杂的表单,这往往会变成一个痛点。于是就想着开发一个可以list来配置的表单组件。

先上组件代码

<!-- 该组件 VUE 版本在 3.4 以上可使用-->
<template>
  <Form
    ref="formRef"
    :model="model"
    v-bind='form'>
    <Row :gutter="[8, 8]">
      <template v-for="config in newConfigs" :key="config.key">
        <Col v-bind="config.wrapperCol" v-if="config.when(model)">
          <Form.Item v-bind="config.forImteAttrs"
            :label-col="config.labelCol">
            <component
              :is="config.type"
              v-bind="config.componentAttrs"
              :config="config"
              :raw="config.raw"
              :options="config.componentAttrs.options || options?.[config.key]"
              v-model:[config.model]="model[config.key]"
              v-on='{
                change: (e: any) => {
                  change(e, config.key);
                  config.componentAttrs.onChange?.({
                    update: change,
                    value: model
                  })
                }
              }'>
              {{ config.componentAttrs.buttonText || null }}
            </component>
          </Form.Item>
        </Col>
      </template>
      <slot />
    </Row>
  </Form>
</template>

<script setup lang="ts">
import {
  Col,
  Form,
  FormInstance,
  Row,
} from 'ant-design-vue';
import {
  computed, Ref,
  toRefs,
  useAttrs,
} from 'vue';
import { FormItemConfig } from './ConfigFormType';

const formRef = defineModel<Ref<null | undefined> | FormInstance>('formRef');
const model = defineModel<any>();

interface IConfigFormProps {
  layout?: 'inline' | 'vertical' | 'horizontal';
  FormGrid?: {};
  labelCol?: any;
  wrapperCol?: any;
  form?: any;
  configs: FormItemConfig[];
  options?: { [index: string]: any[] }
  readonly?: boolean;
}
const props = defineProps<IConfigFormProps>();
const {
  configs, FormGrid, labelCol, options, wrapperCol, readonly,
} = toRefs(props);

const generateUUID = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
  // eslint-disable-next-line no-bitwise
  const r = Math.random() * 16 | 0;
  // eslint-disable-next-line no-bitwise, no-mixed-operators
  const v = c === 'x' ? r : (r & 0x3) | 0x8;
  return v.toString(16);
});

const gloablAttrs = useAttrs();
const newConfigs = computed(() => configs.value.map((config: any) => {
  const {
    grid, key, type, attrs, itemModel, when, children, ...rest
  } = config;
  if (key) {
    rest.name = key;
  }
  if (!config.wrapperCol) {
    rest.wrapperCol = wrapperCol.value;
  }
  if (!config.labelCol) {
    rest.labelCol = labelCol.value;
  }
  const forImteAttrs: Partial<any> = rest;
  const componentAttrs = attrs || {};
  return {
    layout: { ...FormGrid, ...grid },
    name: [key || rest.name],
    key: key || rest.name || generateUUID(),
    when: when || (() => true),
    type,
    children,
    model: itemModel!,
    forImteAttrs,
    wrapperCol: rest.wrapperCol,
    labelCol: rest.labelCol,
    componentAttrs,
    readonly: gloablAttrs.readonly || readonly.value,
    disabled: gloablAttrs.disabled,
    raw: config,
  };
}));

interface IConfigFormEmits {
  (e: 'finish', value: any): void;
  (e: 'change', value: any): void;
}
const emit = defineEmits<IConfigFormEmits>();
const change = (e: any, key: string) => emit('change', { value: e, key });
</script>

具体使用

<ConfigForm
	:configs="configComputed"
	v-model:formRef="formRef"
	v-model="formState"
	@finish="fetchInfo"
	layout="inline" />

configs
用来生成表单的具体配置,类型如下

// FormItemConfig.ts
import { ColProps } from 'ant-design-vue';
import { Slot } from 'vue';

export type FormItemConfig = {
  title?: string;
  type: any;
  layout?: 'horizontal' | 'vertical' | 'inline';
  key?: string;
  name?: string;
  label?: string;
  rules?: any[] | any;
  colon?: boolean;
  options?: any[];
  hasFeedback?: boolean;
  help?: string | Slot;
  labelAlign?: 'left' | 'right';
  labelCol?: ColProps;
  required?: boolean;
  tooltip?: string | Slot;
  validateFirst?: boolean;
  validateStatus?: 'success' | 'warning' | 'error' | 'validating';
  validateTrigger?: string | string[];
  wrapperCol?: ColProps;
  extra?: string | Slot | any;
  model?: any;
  // eslint-disable-next-line no-unused-vars
  when?: (values: Partial<any>, currentValue?: Partial<any>) => boolean;
  itemModel?: string;
  attrs?: Partial<any>;
  children?: FormItemConfig[];
};

configs配置
1、attrs属性为绑定到具体表单组件的属性,例如Select,Input之类的
2、其余大部分属性绑定到<Form.Item>组件上,故可以使用label,rules之类的属性,
3、itemModel一般情况下为value,type为Switch组件时,需根据实际情况变化
4、type属性是直接注入< components >组件的is属性上,所以一些自定义的组件也可以使用,注入到type组件中

import {
  AutoComplete, Button, Spin,
} from 'ant-design-vue';
import {ref } from 'vue';

const autoCompleteLoading = ref<boolean>(false)
const configs = [
    {
      title: 'XXX',
      key: 'name',
      type: autoCompleteLoading.value ? Spin : AutoComplete,
      label: 'item 1',
      rules: { required: true, message: '请输入XXX', trigger: 'blur' },
      itemModel: 'value',
      attrs: {
        options: [{ label: 'item1', value: 'value1' }],
        allowClear: true,
        placeholder: 'XXXXXXXX',
        style: 'width: 280px',
        filterOption: (inputValue: string, option: any) => option.value
          .toLowerCase()
          .indexOf(inputValue.toLowerCase()) >= 0,
      },
    },
    {
      title: 'XXXXXXX',
      type: Button,
      attrs: {
        type: 'primary',
        htmlType: 'submit',
        buttonText: '查询',
      },
    },
   	];

也可以配合计算属性和响应式函数动态响应表单

// config.ts
import { computed, Ref } from 'vue';
import {
  AutoComplete, Button, Spin,
} from 'ant-design-vue';


export function useConfigComputed(
	autoCompleteLoading:Ref<boolean>,
	dataNameList: Ref<{ label: string, value: any }[]>
) {
  return computed(() => [
    {
      title: 'XXX',
      key: 'name',
      type: autoCompleteLoading.value ? Spin : AutoComplete,
      label: 'item 1',
      rules: { required: true, message: '请输入XXX', trigger: 'blur' },
      itemModel: 'value',
      attrs: {
        options: [{ label: 'item1', value: 'value1' }],
        allowClear: true,
        placeholder: 'XXXXXXXX',
        style: 'width: 280px',
        filterOption: (inputValue: string, option: any) => option.value
          .toLowerCase()
          .indexOf(inputValue.toLowerCase()) >= 0,
      },
    },
    {
      title: 'XXXXXXX',
      type: Button,
      attrs: {
        type: 'primary',
        htmlType: 'submit',
        buttonText: '查询',
      },
    },
  ]);
}


// index.vue <script setup lang='ts'>
const autoCompleteLoading = ref<boolean>(false);
const dataNameList = ref<{ label: string, value: any }[]>([]);
const configs = useConfigComputed(
	autoCompleteLoading,
	dataNameList,
)

世纪的使用情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI绘画】Midjourney进阶:景别详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;为什么要学习景别景别的作用景别应用实例 &#x1f4af;大景别&#x1f4af;远景特点提示词书写技巧测试 &#x1f4af;全景特点提示词书写技巧测试注意点 &#x1f…

ozon免费选品工具,OZON免费选品神器

在跨境电商的浩瀚海洋中&#xff0c;寻找那片属于自己的盈利蓝海&#xff0c;是每个商家梦寐以求的目标。随着俄罗斯电商市场的迅速崛起&#xff0c;Ozon平台以其庞大的用户基数和不断增长的市场份额&#xff0c;成为了众多跨境卖家眼中的“香饽饽”。然而&#xff0c;面对琳琅…

【渗透测试】——DVWA靶场搭建

&#x1f4d6; 前言&#xff1a;DVWA&#xff08;Damn Vulnerable Web Application&#xff09;是一个用于安全漏洞测试的 PHP/MySQL 网络应用&#xff0c;旨在为安全专业人士提供一个合法的环境&#xff0c;以测试他们的技能和工具&#xff0c;同时帮助 Web 开发者更好地理解 …

计算机的信息编码和基本运算(上)

大家好我是清墨&#xff0c;今天同同同样来分享一下笔记。 计算机的信息编码 计算机用二进制编码的方式来表示和存储信息&#xff0c;我们见到的信息&#xff08;文字、图片等&#xff09;都是经过转换处理的。 ASCII&#xff08;American Standard Code for Information Int…

[001-02-001]. 第07-02节:线程的创建与使用

我的后端学习大纲 我的Java学习大纲 1、方式1&#xff1a;继承Thread类&#xff1a; 1.1.实现步骤 1.创建一个继承于Thred()类的子类2.重写Thread类的run()3.创建Thread类的子类的对象4.通过这个对象去调用start()方法 在调用start方法时就做了两件事&#xff0c;分别是&…

贪心问题———区间覆盖

输入样例&#xff1a; 1 5 3 -1 3 2 4 3 5 输出样例&#xff1a; 2 分析&#xff1a; 我们根据贪心的思路&#xff0c;能覆盖更大的范围就意味着能用更少的区间段 我们将线段从左端点进行排序 代码演示&#xff1a; #include <iostream> #include <vector>…

从0开始的算法(数据结构和算法)基础(十一)

回溯算法 什么是回溯算法 回溯算法&#xff0c;根据字面意思来理解这个算法是将每一步的操作可以进行回溯&#xff0c;实际上是对这个每一步的操作进行记录&#xff0c;确保可以返回上一步的操作&#xff0c;可能是对回溯操作之前的做一个复现&#xff0c;也有可能是可操作的回…

STM32与ESP8266的使用

串口透传 “透传”通常指的是数据的透明传输&#xff0c;意思是在不对数据进行任何处理或修改的情况下&#xff0c;将数据从一个接口转发到另一个接口。值得注意的是要避免串口之间无限制的透明&#xff0c;可以采用互斥锁的方式进行限制使用方法 对USART1和USART3(用他俩举例…

高效物流管理从固乔快递批量查询助手开始

固乔快递批量查询助手&#xff1a;物流管理的智能化升级 固乔快递查询助手&#xff1a;批量追踪&#xff0c;物流无忧 轻松应对海量单号&#xff0c;固乔快递批量查询助手来帮忙 跨境电商新利器&#xff1a;固乔快递批量查询助手 高效物流管理从固乔快递批量查询助手开始 …

Spring-AOP核心源码、原理详解前篇

本文主要分4部分 Aop原理介绍介绍aop相关的一些类通过源码详解aop代理的创建过程通过源码详解aop代理的调用过程Aop代理一些特性的使用案例 Spring AOP原理 原理比较简单&#xff0c;主要就是使用jdk动态代理和cglib代理来创建代理对象&#xff0c;通过代理对象来访问目标对象…

漏洞复现-泛微-E-Cology-SQL

更多漏洞分析复现&#xff0c;可前往无问社区查看http://www.wwlib.cn/index.php/artread/artid/10358.html 0x01 产品简介 泛微e-cology是一款由泛微网络科技开发的协同管理平台&#xff0c;支持人力资源、财务、行政等多功能管理和移动办公。 0x02 漏洞概述 泛微e-cology…

路由器WAN口和LAN口有什么不一样?

“ 路由器WAN口和LAN口的区别&#xff0c;WAN是广域网端口&#xff0c;LAN是本地网端口。WAN主要用于连接外部网络&#xff0c;而LAN用来连接家庭内部网络&#xff0c;两者主要会在标识上面有区别。以往大部分路由器的WAN只有一个&#xff0c;LAN口则有四个或以上&#xff0c;近…

shader 案例学习笔记之偏移

效果 代码 #ifdef GL_ES precision mediump float; #endifuniform vec2 u_resolution; uniform float u_time;vec2 brickTile(vec2 _st, float _zoom){_st * 5.;_st.x step(1., mod(_st.y,2.0)) * 0.5;return fract(_st); }float box(vec2 _st, vec2 _size){_size vec2(0.5)…

红帽9中nginx-源码编译php

什么是PHP-FPM&#xff1f; PHP-FPM(FastCGI Process Manager&#xff1a; FastCGI进程管理器)是一个实现了Fastcgi的程序&#xff0c;并且提供进程管理的功能。 进程包括master进程和worker进程。master进程只有一个&#xff0c;负责监听端口&#xff0c;接受来自web server 的…

Linux进程(2)(进程状态 - 僵尸、孤儿进程)

目录 1.进程状态 1&#xff09;直接谈论Linux的进程状态 R &#xff1a;进程运行的状态 S &#xff1a;休眠状态 &#xff08;进程在等待“资源”就绪&#xff1b;可中断睡眠&#xff09; T / t &#xff1a;让进程暂停&#xff0c;等待被进一步唤醒 D …

【springboot】整合spring security 和 JWT

目录 1. 整合spring security 1. 导入依赖 2. 配置类 3. 实体类实现UserDetails接口 4. 业务逻辑实现类实现UserDetailsService接口 5. 控制类实现登录功能 6. 测试登录功能 2. 分析源码 1. UsernamePasswordAuthenticationToken 2. A…

【c/c++】类型转换:隐式类型转换、强制类型转换

目录 前言 一、了解类型转换 二、隐式类型转换 1.适用场景 2.转换规则 三、强制类型转换 适用场景 使用规则 注意事项 前言 类型转换是编程中一个常见的现象。在我们进行编码的时候不经意间就发生了&#xff0c;但却能让整个程序运行得更加流畅。 但是这种不经意&am…

C++:STL之vector

1.vector的使用 1.1vector的定义 使用vector需要包含头文件 #include<vector> vector的构造 &#xff08;constructor&#xff09;构造函数声明接口说明vector() (重点)无参构造vector(size_type n,const value_type& val value_type())用n个val初始化并构造vecto…

Java11环境安装(Windows)

目录 1 Java11安装2 配置2.1 JavaHome配置2.2 CLASSPATH配置PATH路径配置 3 验证 1 Java11安装 从官网下载Java11安装包&#xff1a;jdk-11_windows-x64_bin.exe,安装时选择安装到D:\Java目录。 安装完目录结构如下&#xff1a; 2 配置 2.1 JavaHome配置 如下图所示配置JAV…

Ubuntu构建只读文件系统

本文介绍Ubuntu构建只读文件系统。 嵌入式系统使用过程中&#xff0c;有时会涉及到非法关机&#xff08;比如直接关机&#xff0c;或意外断电&#xff09;&#xff0c;这可能造成文件系统损坏&#xff0c;为了提高系统的可靠性&#xff0c;通常将根文件系统设置为只读&#xf…