赞
踩
src
目录创建components
文件夹,并创建dynamic-form.vue
文件dynamic-form.vue
文件封装动态表单控件,根据传入的参数类型显示指定的表单控件,如文本框、下拉框、多选框等等<div> <a-form :form="form" ref="form" :label-col="labelCol" :wrapper-col="wrapperCol"> <div v-for="field in fieldItemOptions" :key="field.key"> <a-form-item :label="field.label" :required="field.required"> <!-- text文本框 --> <template v-if="field.type === 'text'"></template> <!-- textarea 文本域 --> <template v-else-if="field.type === 'textarea'"></template> <!-- select下拉框 --> <template v-else-if="field.type === 'select'"></template> <!-- checkbox多选框 --> <template v-else-if="field.type === 'checkbox'"></template> <!-- radio单选框 --> <template v-else-if="field.type === 'radio'"></template> <!-- 其他表单控件 --> </a-form-item> </div> </a-form> </div>
<template> <div> <a-form :form="form" ref="form" :label-col="labelCol" :wrapper-col="wrapperCol"> <div v-for="field in fieldItemOptions" :key="field.key"> <a-form-item :label="field.label" :required="field.required"> <!-- text文本框 --> <template v-if="field.type === 'text'"> <a-input v-decorator="[ field.key, { rules: [{ required: field.required, message: `${field.label}不能为空` }], initialValue: field.value }, ]" :placeholder="`请输入${field.label}`" ></a-input> </template> <!-- textarea 文本域 --> <template v-else-if="field.type === 'textarea'"> <a-textarea v-decorator="[ field.key, { rules: [{ required: field.required, message: `${field.label}不能为空` }], initialValue: field.value }, ]" :placeholder="`请输入${field.label}`" :auto-size="{ minRows: field.minRows || 5, maxRows: field.maxRows || 8 }" :maxLength="field.max || 256" /> </template> <!-- select下拉框 --> <template v-else-if="field.type === 'select'"> <a-select :placeholder="`请选择${field.label}`" v-decorator="[ field.key, { rules: [{ required: field.required, message: `请选择${field.label}` }], initialValue: field.value }, ]" > <a-select-option v-for="option in field.options" :key="option.value" :value="option.value" >{{option.label}}</a-select-option> </a-select> </template> <!-- checkbox多选框 --> <template v-else-if="field.type === 'checkbox'"> <a-checkbox-group v-decorator="[ field.key, { rules: [{ required: field.required, message: `请选择${field.label}` }], initialValue: field.value }, ]" > <a-checkbox v-for="option in field.options" :key="option.value" :value="option.value" :style="{width: field.width}" >{{option.label}}</a-checkbox> </a-checkbox-group> </template> <!-- radio单选框 --> <template v-else-if="field.type === 'radio'"> <a-radio-group v-decorator="[ field.key, { rules: [{ required: field.required, message: `请选择${field.label}` }], initialValue: field.value }, ]" > <a-radio v-for="option in field.options" :key="option.value" :value="option.value" >{{option.label}}</a-radio> </a-radio-group> </template> </a-form-item> </div> </a-form> <a-button type="primary" @click="handleSubmit()">提交</a-button> </div> </template> <script> import { deepClone } from "@/common/utils"; export default { props: { // 表单域配置 fieldOptions: { type: Array, default: () => [] }, // 编辑时表单回显的默认数据 model: { type: Object, default: () => ({}) }, // 标签宽度 labelCol: { type: Object, default: () => { return { xs: { span: 24 }, sm: { span: 6 } }; } }, // 控件宽度 wrapperCol: { type: Object, default: () => { return { xs: { span: 24 }, sm: { span: 16 } }; } } }, watch: { fieldOptions: { handler(fieldOptions) { this.fieldItemOptions = deepClone(fieldOptions); this.fieldItemOptions.forEach(c => { for (const key in this.model) { if (c.key === key) { c.value = this.model[key]; } } }); }, deep: true, immediate: true } }, data() { return { fieldItemOptions: [], // 表单 form: this.$form.createForm(this) }; }, methods: { // 提交表单 handleSubmit() { this.form.validateFields((err, formData) => { if (err) { return; } // 提交表单逻辑 }); } }, created() {} }; </script>
model
为空对象,一般用于新增操作<template> <div> <dynamic-form ref="dynamicForm" :fieldOptions="fieldOptions" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" ></dynamic-form> </div> </template> <script> import DynamicForm from "./dynamic-form.vue"; export default { components: { DynamicForm }, data() { return { fieldOptions: [ { label: "姓名", key: "name", value: "", type: "text", required: true }, { label: "性别", key: "sex", value: 1, type: "radio", required: true, options: [ { value: 1, label: "男" }, { value: 2, label: "女" } ] }, { label: "兴趣爱好", key: "hobby", value: [], type: "checkbox", required: true, options: [ { value: 1, label: "足球" }, { value: 2, label: "篮球" }, { value: 3, label: "排球" } ] }, { label: "国家", key: "country", value: undefined, type: "select", required: true, options: [ { value: 1, label: '中国' }, { value: 2, label: '美国' }, { value: 3, label: '俄罗斯' } ] }, { label: "个人简介", key: "desc", value: "", type: "textarea", required: false } ], // 表单默认内容 model: { // name: '动态表单', // sex: 2, // hobby: [1, 2], // country: 1, // desc: '这是一个简单的例子' }, labelCol: { xs: { span: 24 }, sm: { span: 6 } }, wrapperCol: { xs: { span: 24 }, sm: { span: 16 } } }; } }; </script>
5. 若表单有默认内容,需要回显,通常用于编辑操作,只需要给model
对应的键添加值即可
附:深克隆函数deepClone
const getRegExp = (re) => { var flags = ""; if (re.global) flags += "g"; if (re.ignoreCase) flags += "i"; if (re.multiline) flags += "m"; return flags; }; const isType = (obj, type) => { if (typeof obj !== "object") return false; const typeString = Object.prototype.toString.call(obj); let flag; switch (type) { case "Array": flag = typeString === "[object Array]"; break; case "Date": flag = typeString === "[object Date]"; break; case "RegExp": flag = typeString === "[object RegExp]"; break; default: flag = false; } return flag; }; export const deepClone = (parent) => { // 维护两个储存循环引用的数组 const parents = []; const children = []; const _clone = (parent) => { if (parent === null) return null; if (typeof parent !== "object") return parent; let child, proto; if (isType(parent, "Array")) { // 对数组做特殊处理 child = []; } else if (isType(parent, "RegExp")) { // 对正则对象做特殊处理 child = new RegExp(parent.source, getRegExp(parent)); if (parent.lastIndex) child.lastIndex = parent.lastIndex; } else if (isType(parent, "Date")) { // 对Date对象做特殊处理 child = new Date(parent.getTime()); } else { // 处理对象原型 proto = Object.getPrototypeOf(parent); // 利用Object.create切断原型链 child = Object.create(proto); } // 处理循环引用 const index = parents.indexOf(parent); if (index != -1) { // 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象 return children[index]; } parents.push(parent); children.push(child); for (let i in parent) { // 递归 child[i] = _clone(parent[i]); } return child; }; return _clone(parent); };
拓展
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。