# 表单 FormAuto

解决表单交互中开发重复性高、配置复杂等问题。

# 基础表单

{}
{}
验证规则 重置 编辑
<template>
	<div>
		<el-card shadow="never" header="内联表单" style="margin-bottom: 15px;">
			<el-form-auto
				:data="filterForm"
				ref="FilterForm"
				v-model="filterModel"
				label-width="70px"
				inline
			></el-form-auto>
			<div>{{filterModel}}</div>
		</el-card>
		<el-card shadow="never" header="栅格表单(应用 el-row 可对表单项进行布局)">
			<el-form-auto :data="form" ref="EditForm" v-model="model" label-width="120px">
				<div>{{model}}</div>
				<el-button type="primary" @click="getValidModel">验证规则</el-button>
				<el-button type="default" @click="reset">重置</el-button>
				<el-button type="primary" @click="edit">编辑</el-button>
			</el-form-auto>
		</el-card>
	</div>
</template>
<script>
var defaultOption = [
	{
		label: "选项1",
		value: 0
	},
	{
		label: "带图标选项3",
		icon: "el-icon-help",
		value: 3
	},
	{
		label: "选项禁用2",
		value: 2,
		disabled: true
	},
	"选项2"
];
export default {
	data() {
		return {
			filterForm: {
				account: {
					label: "文本框",
					type: "text"
				},
				date: {
					label: "日期",
					type: "date"
				},
				dateRange: {
					label: "日期范围",
					type: "datetimerange",
					rangeName: ["startDate", "endDate"]
				},
				numberrange: {
					label: "金额范围",
					type: "numberrange",
					rangeName: ["min", "max"]
				},
				status: {
					label: "选择框",
					type: "select",
					options: { 1: "正常", 2: "禁用" }
				},
				radiobutton: {
					label: "选择框",
					type: "radiobutton",
					options: { 1: "正常", 2: "禁用" }
				}
			},
			filterModel: {},
			model: {},
			form: {
				id: {
					label: "id",
					type: "hidden"
				},
				switch: {
					col: 12,
					label: "开关",
					type: "switch",
					required: true
				},
				slider: {
					col: 12,
					label: "滑块",
					type: "slider",
					value: 10,
					required: true
				},
				sliderRange: {
					col: 12,
					label: "滑块",
					type: "slider",
					range: true,
					required: true
				},
				text: {
					col: 12,
					label: "文本框",
					labelTooltip: "labelTooltip属性可以在标签旁增加图标,提示字段含义",
					type: "text",
					required: true
				},
				password: {
					col: 12,
					label: "密码框",
					type: "password",
					required: true,
					addRules: [
						{
							pattern: /^(?=.*[a-zA-Z])(?=.*\d)[^]{8,16}$/,
							message: "需要8位~16位以内,包含字母与数字的字符"
						}
					]
				},
				cascader: {
					col: 12,
					label: "级联框",
					type: "cascader",
					required: true,
					props: {
						emitPath: false
					},
					options: [
						{
							label: "节点1",
							value: 1,
							children: [
								{
									label: "节点4",
									value: 4,
									children: [{ label: "节点5", value: 5 }]
								}
							]
						},
						{
							label: "节点2",
							value: 2,
							children: [{ label: "节点6", value: 6 }]
						},
						{ label: "节点3", value: 3 }
					]
				},
				select: {
					col: 12,
					label: "选择框",
					type: "select",
					required: true,
					options: defaultOption
				},
				date: {
					col: 12,
					label: "日期",
					type: "date",
					required: true
				},
				dates: {
					col: 12,
					label: "多个日期",
					type: "dates",
					required: true
				},
				months: {
					col: 12,
					label: "多个月份",
					type: "months",
					required: true
				},
				years: {
					col: 12,
					label: "多个年份",
					type: "years",
					required: true
				},
				datetime: {
					col: 12,
					label: "日期时间",
					type: "datetime",
					required: true
				},
				time: {
					col: 12,
					label: "时间",
					type: "time",
					required: true
				},
				timeSelect: {
					col: 12,
					label: "时间选择",
					type: "timeselect",
					required: true,
					style: "width:100%"
				},
				timeRange: {
					col: 12,
					label: "时间范围",
					type: "timerange",
					rangeName: ["startTime", "endTime"],
					required: true
				},
				dateRange: {
					col: 12,
					label: "日期范围",
					type: "daterange",
					rangeName: ["startDate", "endDate"],
					required: true
				},
				monthRange: {
					col: 12,
					label: "月份范围",
					type: "monthrange",
					rangeName: ["startDate", "endDate"],
					required: true
				},
				datetimeRange: {
					label: "日期时间范围",
					type: "datetimerange",
					rangeName: ["startDT", "endDT"],
					required: true
				},
				radio: {
					label: "单选框",
					type: "radio",
					required: true,
					options: defaultOption
				},
				radiobutton: {
					label: "单选按钮",
					type: "radiobutton",
					options: defaultOption,
					required: true
				},
				check: {
					label: "复选框",
					type: "check",
					required: true,
					options: { 1: "选项1", 2: "选项2", 3: "选项3" }
				},
				rate: {
					label: "评分",
					type: "rate",
					required: true
				},
				textarea: {
					label: "备注",
					type: "textarea",
					minlength: 5,
					maxlength: 10,
					showWordLimit: true
				}
			}
		};
	},
	methods: {
		reset() {
			this.$refs["EditForm"].reset();
		},
		edit() {
			this.form.password.disabled = true;
			this.model = {
				id: "123",
				plain: "无需提交",
				switch: 0,
				slider: 23,
				text: "文本",
				password: "password123456",
				textarea: null,
				date: "2021-01-10",
				dates: ["2021-01-10", "2021-01-12"],
				datetime: "2021-01-10 11:11:00",
				dateRange: ["2021-01-10", "2021-01-13"],
				datetimeRange: ["2021-01-10 11:11:00", "2021-01-12 13:11:00"],
				time: "11:11:00",
				timeSelect: "11:00",
				timeRange: ["11:11:00", "22:12:00"],
				select: 0,
				check: ["1"],
				radiobutton: 0,
				radio: 3,
				cascader: [2, 6],
				rate: 5
			};
		},
		async getValidModel() {
			try {
				await this.$refs["EditForm"].validate();
			} catch {}
		}
	}
};
</script>
显示代码 复制代码

# 对组件增加的预设

  1. 所有日期时间相关组件 valueFormat 增加 unix 10 位时间戳转化功能,并对 valueFormat 增加默认值。

    原因是我也不知道为什么 JS 要多出 3 位毫秒,而后端时间格式可以如此多的想法。😭

  2. daterange|timerange|datetimerange|numberrange|slider对应组件增加 rangeName 属性,方便快速迭代到对应接口传参内。
  3. slider对应组件增加 range 属性时,默认值为组件的 [min, max]
  4. select组件远程搜索 remote: true 时 清空 或 搜索结果为空,再次点击下拉选框将重置筛选并重新请求。
{}
<template>
	<el-form-auto :data="form" ref="EditForm" v-model="model" label-width="110px">{{ model }}</el-form-auto>
</template>
<script>
export default {
	data() {
		return {
			form: {
				date: {
					label: "日期",
					type: "date",
					value: "2011-06-08"
				},
				daterange: {
					label: "日期范围",
					type: "daterange",
					rangeName: ["startDate", "endDate"],
					defaultTime: ["00:00:00", "23:59:59"]
				},
				daterangeUnix: {
					label: "unix日期范围",
					type: "daterange",
					rangeName: ["startUnixDate", "endUnixDate"],
					valueFormat: "unix",
					value: [1665763200000, 1666022400000]
				},
				dates: {
					label: "多个日期",
					type: "dates",
					valueFormat: "unix",
					value: [1307462400000]
				},
				time: {
					label: "时间",
					type: "time",
					valueFormat: "unix"
				},
				timeselect: {
					label: "时间",
					type: "timeselect"
				},
				timerange: {
					label: "时间范围",
					type: "timerange",
					valueFormat: "unix",
					rangeName: ["startTime", "endTime"]
				},
				slider: {
					label: "范围",
					type: "slider",
					range: true,
					rangeName: ["startNum", "endNum"],
					min: 1,
					max: 7
				}
			},
			model: {}
		};
	}
};
</script>
显示代码 复制代码

# 绑定显隐

表单项增加 bindShow 属性,解决复杂表单交互

{}
<template>
  <el-form-auto :data="form" v-model="model" label-width="130px">
    <div>{{ model }}</div>
  </el-form-auto>
</template>
<script>
export default {
  data() {
    return {
      model: {},
      form: {
        subject: {
          label: "主体",
          type: "radio",
          required: true,
          options: { person: "个人", company: "企业" },
          value: "person",
        },
        person_name: {
          label: "姓名",
          type: "text",
          required: true,
          bindShow: (model) => {
            return model.subject == "person";
          },
        },
        person_number: {
          label: "身份证",
          type: "text",
          required: true,
          bindShow: (model) => {
            return model.subject == "person";
          },
        },
        company_name: {
          label: "企业名称",
          type: "text",
          required: true,
          bindShow: (model) => {
            return model.subject == "company";
          },
        },
        company_number: {
          label: "统一税务登记号",
          type: "text",
          required: true,
          bindShow: (model) => {
            return model.subject == "company";
          },
        },
      },
    };
  },
};
</script>
显示代码 复制代码

# options 设置

export declare interface ElAutoOption {
  icon?: string;
  label: string;
  type?: "primary" | "warning" | "info" | "danger";
  value: string | number;
  disabled?: boolean;
  children?: ElAutoOption[];
  props?: Record<string, any>;
}
export declare type ElAutoMixinOptions =
  | Record<string | number, string | number>
  | Array<string | ElAutoOption>;
  1. options 标准规范值是 [{label: "苹果", value: "apple", icon:"el-icon-apple", disabled: false }, ...]
  2. options 值为 ["苹果", ...] 文本数组时,labelvalue 皆为 "苹果"
  3. options 值为 {apple: "苹果", banana: "香蕉", ...} 对象时,label 为值 苹果value 为对应键值 apple
  4. options 值为 async () => Promise<ElAutoOption> 的 Promise 函数时,返回值按 1~3 条规则匹配。
  5. type: "select"options 值为 (query?,page?) => Promise<ElAutoOption> 的 Promise 函数时,返回值同样按 1~3 条规则匹配。 remote: true 时 query 值提供搜索关键字, loadScroll:true 时 page 值提供加载页码
  6. type: "cascader" 级联选择框只支持应用标准规范值。
{}

<template>
	<el-form-auto :data="form" ref="EditForm" v-model="model">
		<div>{{ model }}</div>
	</el-form-auto>
</template>
<script>
export default {
	data() {
		return {
			model: {},
			form: {
				asyncSelect: {
					label: "可滚动加载的搜索选项框",
					type: "select",
					filterable: true,
					remote: true,
					loadScroll: true,
					options: (query = "", page = 1) => {
						if (page > 3) return [];
						return axios
							.get(`https://jsonplaceholder.typicode.com/users`)
							.then(res => {
								return res.data.reduce((res, item) => {
									// if (item.username.indexOf(query) > -1) {
									res.push({
										label: item.username,
										value: item.id * page
									});
									// }
									return res;
								}, []);
							});
					}
				},
				selectName: {
					type: "hidden"
				},
				select: {
					label: "选择框",
					type: "select",
					options: () => {
						return axios
							.get("https://jsonplaceholder.typicode.com/users")
							.then(res => {
								return res.data.map(item => {
									return {
										label: item.username,
										value: item.id
									};
								});
							});
					},
					on: {
						change: val => {
							this.$nextTick(function(){
								this.model.selectName = this.$refs["EditForm"].getOptions(
									"select"
								)[val].label;
							})
							return val;
						}
					}
				},
				remoteCascader: {
					label: "级联框",
					type: "cascader",
					props: { label: "name", value: "id", children: "childrenList" },
					options: () => {
						return axios
							.get("/element-ui-saas-extend/json/cascader.json")
							.then(res => {
								return res.data;
							});
					}
				},
				radio: {
					col: 12,
					label: "单选框",
					type: "radio",
					notAll: true,
					options: ["单选1", "单选2", "单选3"]
				},
				check: {
					label: "复选框",
					type: "check",
					options: [
						"复选1",
						"复选2",
						{
							label: "带图标复选3",
							value: 3,
							icon: "el-icon-help"
						}
					]
				}
			}
		};
	}
};
</script>
显示代码 复制代码

# 远程选择框的回显

type 为 select 并且 开启远程搜索的功能时,需要提供回显能力。清空时,默认删除回显值

远程搜索选项回显 重置
{}

<template>
	<el-form-auto :data="form" ref="EditForm" v-model="model" label-width="90px">
		<el-button type="primary" @click="editOptionReshow">远程搜索选项回显</el-button>
		<el-button type="primary" @click="reset">重置</el-button>
		<div>{{ model }}</div>
	</el-form-auto>
</template>
<script>
export default {
	data() {
		let getOptions = (query, page) => {
			return axios
				.get("https://jsonplaceholder.typicode.com/users", {
					params: { query, page }
				})
				.then(res => {
					return res.data.reduce((prev, curr) => {
						if (curr.username.indexOf(query) > -1) {
							prev.push({
								label: curr.username,
								value: curr.id * page
							});
						}
						return prev;
					}, []);
				});
		};
		return {
			model: {},
			form: {
				remote: {
					col: 12,
					label: "远程搜索",
					type: "select",
					style: "width:100%",
					required: true,
					loadScroll: true,
					remote: true,
					options: getOptions
				},
				remoteMult: {
					col: 12,
					label: "远程搜索",
					type: "select",
					style: "width:100%",
					multiple: true,
					required: true,
					loadScroll: true,
					remote: true,
					options: getOptions
				}
			}
		};
	},
	methods: {
		editOptionReshow() {
			this.model = {
				remote: { label: "回显测试", value: "echo_show" },
				remoteMult: [
					{ label: "测试", value: "123" },
					{ label: "测试2", value: "1233" }
				]
			};
		},
		reset() {
			this.$refs["EditForm"].reset();
		}
	}
};
</script>
显示代码 复制代码

# 自定义动态插槽

支持对表单项自定义动态插槽,通过设置 slot 属性,可设置booleanstring类型,设置为 true 时,slot 名为属性的字段名,slot 为字符串类型时,多个字段可复用一个插槽,插槽携带参数如下:

  • item 字段属性
  • model 表单 model
  • name 字段名
表单字段: {}
<template>
	<el-form-auto :data="form" v-model="model" label-width="90px">
		<template slot-scope="{ item, model, name }" slot="upload">
			<el-upload
				action="https://jsonplaceholder.typicode.com/upload"
				v-model="model[name]"
				:on-success="uploadSuccess"
			>
				<el-button round type="primary" icon="el-icon-upload">上传文件</el-button>
			</el-upload>
		</template>
		<template slot-scope="{ item, model, name }" slot="color">
			<el-color-picker v-model="model[name]"></el-color-picker>
		</template>
		<div>表单字段: {{ model }}</div>
	</el-form-auto>
</template>
<script>
export default {
	data() {
		return {
			form: {
				user: {
					col: 12,
					label: "选择用户",
					labelTooltip: "自定义的组件,可直接使用",
					type: "component",
					component: "user-selector",
					on: {
						select: item => {
							this.model.id = item.id;
							this.model.name = item.name;
							this.model.phone = item.phone;
							this.model.email = item.email;
						}
					}
				},
				id: {
					col: 12,
					label: "用户ID",
					type: "plain",
					value: "未选择"
				},
				name: {
					col: 12,
					label: "姓名",
					type: "plain",
					value: "未选择"
				},
				phone: {
					col: 12,
					label: "手机",
					type: "plain",
					value: "未选择",
				},
				email: {
					col: 12,
					label: "邮箱",
					type: "plain",
					value: "未选择"
				},
				color1: {
					col: 12,
					label: "颜色1",
					type: "text",
					slot: "color"
				},
				color2: {
					col: 12,
					label: "颜色2",
					type: "text",
					slot: "color"
				},
				upload: {
					label: "上传",
					slot: true,
					type: "text"
				}
			},
			model: {}
		};
	},
	methods: {
		uploadSuccess(res, file, filelist) {
			this.model.upload = "上传返回URL";
		}
	}
};
</script>
显示代码 复制代码

# 属性

# Props

参数 描述 类型 可选值 默认值
v-model 表单数据对象 object - {}
data 表单项配置 Record<name:string,FormAutoField> - {}
gutter <el-row> 属性 gutter number - 15
over-collapse 超出 设定值 表单项隐藏 number / boolean - false
[prop:string] 继承 el-form 所有 Prop any - -

# FormAutoField

参数 描述 类型 默认值
标签相关设置
label 标签名 string -
labelHidden 是否隐藏标签 boolean false
labelTooltip 表单项提示 string / boolean false
labelWidth 标签宽度 string -
value 字段默认值 any -
控件相关设置
type 必填,控件类型 参照 type Enum 表 -
slot 自定义动态插槽,设为 true 时,slot 为 name,详情可参考 自定义动态插槽示例 string / boolean false
component 组件名称,type 为 component 时有效 string -
[prop:string] 可直接追加 type 对应组件的 prop any -
disabled 是否禁用字段 boolean false
placeholder 占位符 array -
on 设置 type 对应组件的事件 object {}
rangeName 日期范围名 type 为 daterange/timerange/datetimerange/numberrange/slider 选填 array<string> false
suffixTime type 为 daterange 选填,为日期范围增加 00:00:00 - 23:59:59 boolean false
valueFormat type 为 日期类控件 选填,格式与 element-ui 一致,增加 unix 10 位时间戳格式 string -
options type 为 check/radio/select 必填,详情可参考 options 设置 object / array / Promise []
allOption type 为 select/radio/radiobutton 有效,为选项框增加 全部 option boolean false
remote 支持接口搜索,type 为 select 有效 boolean false
notAll 不显示全选,type 为 check 有效 boolean false
表单相关设置
col 占用栅格 number 24
required 是否必填 boolean false
ruleType 为 async-validator 必填设置另外配置类型 string -
bindShow 绑定显示 (model)=>boolean -
addRules 追加验证规则 array -

# type Enum

对应组件 描述
text <el-input type="text"> 文本输入框
password <el-input type="password"> 密码输入框
textarea <el-input type="textarea"> 文本域
number <el-input-number> 计数器
numberrange <el-number-range> 数值范围
date <el-date-picker type="date"> 日期选择
year <el-date-picker type="year"> 年份选择
years <el-date-picker type="years"> 多年份选择
month <el-date-picker type="month"> 月份选择
months <el-date-picker type="months"> 多月份选择
week <el-date-picker type="week"> 周选择
dates <el-date-picker type="dates"> 多日期选择
datetime <el-date-picker type="datetime"> 日期时间选择
daterange <el-date-picker type="daterange"> 日期范围选择
monthrange <el-date-picker type="date"> 月份范围选择
datetimerange <el-date-picker type="datetimerange"> 日期时间范围选择
time <el-time-picker> 时间选择
timerange <el-time-picker is-range> 时间范围选择
radio <el-radio> 单选框
radiobutton <el-radio-button> 单选框
check <el-checkbox> 复选框
select <el-select> 选择框
slider <el-slider> 滑动选择框
switch <el-switch> 开关
cascader <el-cascader> 多级选择框
rate <el-rate> 评分
component <component :is="item.component"> 自定义组件

# Method

方法名 描述 参数
reset() 重置表单 -
refreshOptions() 刷新选项 (fieldName: string, clearEcho:boolean=true)=>void
validate() 对整个表单进行校验的方法 Promise<void> | (valid:boolean)=>void
validateField() 对整个表单进行校验的方法 (prop:string,callback:(errMsg:string)=>void)=>void
getModel() 获取表单所有参数 ()=>Record<string,any>
setModel() 设置表单对应参数 (model:Record<string,any>)=>void
getOptions() 获取字段对应的 options,返回 value 为 key 的集合 (name:string)=>Record<string, any>

# Slot

插槽 描述
- 按钮插槽
prepend 表单内首部插槽
append 表单尾部,按钮之前插槽

# Scope Slot

插槽名称 描述
自定义名称 自定义表单项的内容,参数为 { item, model, name }

# Event

事件名称 说明 回调参数
[event:name] 可直接追加 <el-form> 所有事件 -