vue2+jsx二次封装el-form表单

我们在日常工作中,经常遇到多条件的筛选或者是多数据的form,一条一条写起来太费时间+精力,二次封装form之后会大大节省我们的时间,我采用的方法是jsx,render中生成form的形式,废话不多说,直接上代码

1.首先是子组件proform

<script lang="jsx">
import {
  Button,
  Form,
  FormItem,
  Input,
  InputNumber,
  Row,
  Col,
  DatePicker,
  TimePicker,
} from "element-ui";
import Select from "./components/ProSelect.vue";
import RadioGroup from "./components/ProRadioGroup.vue";
import CheckboxGroup from "./components/ProCheckboxGroup.vue";

const componentsMap = {
  Input,
  InputNumber,
  Select,
  RadioGroup,
  CheckboxGroup,
  DatePicker,
  TimePicker,
};

export default {
  props: {
    labelWidth: {
      type: String,
      default: ''
    },
    labelPosition: {
      type: String,
      default: "left",
    },
    gutter: {
      type: Number,
      default: 15
    },
    schemas: {
      type: Array,
      default: () => [],
    },

    formData: {
      type: Object,
      default: () => ({}),
    },
    model: Object,
  },
  created() {
    this.datas = this.schemas.slice(0, 3);
  },
  data() {
    return {
      flag: true,
      datas: [],
    };
  },
  methods: {
    reset() {
      this.$refs.formRef.resetFields();
    },
    validate() {
      return this.$refs.formRef
        .validate()
        .then(() => {
          return this.model;
        })
        .catch((err) => {
          return Promise.reject(err);
        });
    },
  },
  render(h) {
    const { schemas, labelWidth, labelPosition, gutter, model } = this;
    return (
      <Form
        props={{ model: this.model }}
        labelWidth={labelWidth + "px"}
        labelPosition={labelPosition}
        ref="formRef"
      >
        {/* {
        {

        scopedSlots:{
          default: ()=>{

          },
          header: ()=>{

          }
        },
      }

      } */}
        <Row gutter={gutter}>
          {this.datas.map((item) => {
            const rules = [];
            if (item.required) {
              rules.push({ required: true, message: `${item.label}不能为空` });
            }
            return (
              <Col span={item.span}>
                <FormItem label={item.label} prop={item.field} rules={rules}>
                  {h(componentsMap[item.component], {
                    props: {
                      ...item.componentProps,
                      value: this.model[item.field],
                    },
                    on: {
                      input: (newValue) => {
                        this.model[item.field] = newValue;
                      },
                    },
                  })}
                </FormItem>
              </Col>
            );
          })}
          <Col span={6}>
            <FormItem>
              <Button type="primary" onClick={this.validate}>
                查询
              </Button>
              <Button onClick={this.reset}>重置</Button>
              {schemas.length > 3 ? (
                <span>
                  {this.flag ? (
                    <Button type="text" icon="el-icon-arrow-down"
                      onClick={() => {
                        this.flag = false;
                        this.datas = this.schemas;
                      }}
                    >
                      展开
                    </Button>
                  ) : (
                    <Button type="text" icon="el-icon-arrow-up"
                      onClick={() => {
                        this.flag = true;
                        this.datas = this.schemas.slice(0, 3);
                      }}
                    >
                      收起
                    </Button>
                  )}
                </span>
              ) : (
                <div></div>
              )}
            </FormItem>
          </Col>
        </Row>
      </Form>
    );
  },
};
</script>

<style scoped lang="scss">
::v-deep {
  .el-form-item {
    width: 100%;
    display: flex;

    .el-form-item__content {
      flex: 1;
    }

    .el-form-item__label {
      flex-shrink: 0;
      padding-right: 12px;
    }
  }

  .el-col {
    padding: 0 8px;
  }

  .el-date-editor,
  .el-select,
  .el-input {
    width: 100%;
  }
  .el-button {
    margin-right: 10px;
  }
}
</style>

2.然后二次封装其他基础组件比如el-select,el-radio

<script lang="jsx">
import { Select, Option } from 'element-ui'

export default {
  props: {
    value: [String, Array],
    options: {
      type: Array,
      default: () => []
    },
    multiple: {
      type:Boolean
    }

  },
  data() {
    return {}
  },
  computed: {
    model: {
      get() {
        return this.value
      },
      set(newVal) {
        this.$emit('input', newVal)
      }
    }
  },
  render(h) {
    const { model, options, multiple} = this
    return (
      <Select vModel={this.model} clearable multiple={multiple}>
        {options.map((item) => {
          return <Option label={item.label} value={item.value}></Option>
        })}
      </Select>
    )
  }
}
</script>
<script lang="jsx">
import { Radio, RadioGroup} from 'element-ui'
export default {
  props: {
    value: [String, Array],
    options: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {}
  },
  computed: {
    model: {
      get() {
        return this.value
      },
      set(newVal) {
        this.$emit('input', newVal)
      }
    }
  },
  render(h) {
    const { model, options } = this
    return (
      <RadioGroup vModel={this.model}>
        {options.map((item) => {
          return <Radio label={item.label} value={item.value}></Radio>
        })}
      </RadioGroup>
    )
  }
}

</script>
<script lang="jsx">

import { CheckboxGroup, Checkbox } from 'element-ui'

export default {
  props: {
    value: Array,
    options: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
    }
  },
  computed: {
    model: {
      get() {
        return this.value
      },
      set(newVal) {
        this.$emit('input', newVal)
      }
    }
  },
  render(h) {
    const { model, options } = this
    return (
      <CheckboxGroup vModel={this.model}>
        {
          options.map(item => {
            return (
              <Checkbox label={item.label} value={item.value}>
                {item.label}
              </Checkbox>
            )
          })
        }

      </CheckboxGroup>
    )
  }
}
</script>

3.最后父组件引入子组件使用,并传入json

<template>
  <div class="wapper">
    <ProForm
      ref="form"
      form-ref="freeForm"
      :model="formData"
      v-bind="formConfig"
      :rules="rules"
    />
  </div>
</template>

<script>
import { ProForm } from './ProForm '

export default {
  components: {
    ProForm,
  },
  data() {
    return {
      // 表单数据console
      formData: {
        username: "",
        number: 0,
        time: "",
        orgIdProduction: "",
        sex: "",
        love: [],
        developmentMethods: "",
      },
      // el-form-item 配置项
      formConfig: {
        // labelWidth: 100, // 标题宽度
        labelPosition: "left",
        gutter: 12,
        schemas: [
          {
            required: true,
            label: "用户名",
            field: "username",
            component: "Input", // el-input可以省略,默认使用el-input
            placeholder: "请输入用户名", // placeholder可以省略,默认显示“请输入+label”
            span: 6, // 使用栅格布局
          },
          {
            label: "数字输入",
            field: "number",
            component: "InputNumber",
            controlsPosition: "right",
            span: 6, // 使用栅格布局
          },
          {
            label: "所属单位",
            labelWidth: 180, // 标题宽度-优先级高
            component: "Select",
            field: "orgIdProduction",
            span: 6,
            componentProps: {
              multiple: true, // 是否多选
              clearable: true, // 能否清空
              placeholder: "请选择",
              options: [
                {
                  label: "白庄煤矿",
                  value: "01076430",
                },
                {
                  label: "梁宝寺煤矿",
                  value: "01076323",
                },
              ],
            },
            onChange: (value) => {
              console.log(value);
            },
          },

          {
            label: "日期选择",
            field: "time",
            component: "DatePicker",
            type: "datetime",
            span: 6,
            componentProps: {
              width: "100%",
            },
          },
          {
            label: "性别",
            field: "sex",
            span: 6, // 支持栅格布局
            component: "RadioGroup", // 可以传入任意组件
            componentProps: {
              options: [
                {
                  label: "男",
                  value: 1,
                },
                {
                  label: "女",
                  value: 2,
                },
              ],
            },
            onChange: (e) => {
              console.log(e);
            },
          },
          {
            label: "菜单",
            field: "developmentMethods",
            span: 6,
            component: "RadioGroup",
            componentProps: {
              options: [
                {
                  label: "菜单1",
                  value: "menu1",
                },
                {
                  label: "菜单二",
                  value: "menu2",
                },
              ],
              onChange: (e) => {
                console.log(e);
              },
            },
          },
          {
            label: "兴趣爱好",
            field: "love",
            span: 6, // 支持栅格布局
            component: "CheckboxGroup", // 可以传入任意组件
            componentProps: {
              options: [
                {
                  label: "读书",
                  value: 1,
                },
                {
                  label: '菜单二',
                  value: 'menu2'
                }
              ]

            }
          }
        ]
      },
      addFormConfig: {
        labelWidth: 100, // 标题宽度
        labelPosition: 'left',
        gutter: 12,
        schemas: [
          {
            label: '用户名',
            field: 'username',
            component: 'Input', // el-input可以省略,默认使用el-input
            placeholder: '请输入用户名' // placeholder可以省略,默认显示“请输入+label”
          },
          {
            label: '数字输入',
            field: 'number',
            component: 'InputNumber',
            controlsPosition: 'right'
          },
          {
            label: '所属单位',
            labelWidth: 180, // 标题宽度-优先级高
            component: 'Select',
            field: 'orgIdProduction',
            componentProps: {
              multiple: true, // 是否多选
              placeholder: '请选择',
              options: [
                {
                  label: '白庄煤矿',
                  value: '01076430'
                },
                {
                  label: '梁宝寺煤矿',
                  value: '01076323'
                }
              ]
            },
            onChange: (value) => {
              console.log(value)
            }
          },

          {
            label: '日期选择',
            field: 'time',
            component: 'DatePicker',
            type: 'datetime',
            componentProps: {
              width: '100%'
            }
          },
          {
            label: '性别',
            field: 'sex',
            component: 'RadioGroup', // 可以传入任意组件
            componentProps: {
              options: [
                {
                  label: '男',
                  value: 1
                },
                {
                  label: '女',
                  value: 2
                }
              ]
            },
            onChange: (e) => {
              console.log(e)
            }
          },
          {
            label: '兴趣爱好',
            field: 'love',
            component: 'CheckboxGroup', // 可以传入任意组件
            componentProps: {
              options: [
                {
                  label: '读书',
                  value: 1
                },
                {
                  label: '写字',
                  value: 2
                },
                {
                  label: '听歌',
                  value: 4
                }
              ]
            },
            onChange: (e) => {
              console.log(e)
            }
          },
          {
            label: '菜单',
            field: 'developmentMethods',
            component: 'RadioGroup',
            isButton: true,
            clearable: true,
            hidden: true,
            componentProps: {
              options: [
                {
                  label: '菜单1',
                  value: 'menu1'
                },
                {
                  label: '菜单二',
                  value: 'menu2'
                }
              ]

            }
          }
        ]
      },
      // el-form-item 验证规则
    };
  },
  methods: {
    // 级联类型
    changeMajor(type) {
      const json = {
        primary: [
          {
            label: "数学",
            value: 1,
          },
          {
            label: "语文",
            value: 2,
          },
        ],
        junior: [
          {
            label: "英语",
            value: 5,
          },
          {
            label: '生物',
            value: 7
          }
        ]
      }
    },
    openAddFormModal() {
      DetailFormModal.show({
        title: '新增数据',
        schemas: this.addFormConfig.schemas,
        formData: this.formData
      }).then(res => {
        console.log('openAddFormModal', res)
      })
    }
  }
}
</script>

<style>
.wapper {
  background: #fff;
}
</style>

最后:展示效果:

希望能对你有帮助

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里是一个简单的示例,二次封装了 `el-form` 组件,实现了表单验证和表单重置的功能: ```vue <template> <my-form :form-data="formData" :form-rules="formRules" @submit="handleSubmit" @reset="handleReset" /> </template> <script> import MyForm from '@/components/MyForm' export default { components: { MyForm }, data() { return { formData: { username: '', password: '' }, formRules: { username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], password: [{ required: true, message: '请输入密码', trigger: 'blur' }] } } }, methods: { handleSubmit(formData) { // 表单提交处理逻辑 console.log(formData) }, handleReset() { // 表单重置处理逻辑 console.log('表单已重置') } } } </script> ``` `MyForm` 组件的代码如下: ```vue <template> <el-form :model="formData" :rules="formRules" ref="form" label-width="100px"> <slot></slot> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> <el-button @click="resetForm">重置</el-button> </el-form-item> </el-form> </template> <script> export default { props: { formData: Object, formRules: Object }, methods: { submitForm() { this.$refs.form.validate(valid => { if (valid) { // 表单验证通过,提交表单数据 this.$emit('submit', this.formData) } else { // 表单验证失败 console.log('表单验证失败') return false } }) }, resetForm() { this.$refs.form.resetFields() this.$emit('reset') } } } </script> ``` 在 `MyForm` 组件中,使用 `slot` 插槽来实现动态插入表单项,使用 `props` 属性来接收父组件传递的表单数据和表单验证规则,使用 `$emit` 方法来向父组件发送表单提交和表单重置的事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值