当前位置: 首页 > news >正文

表单 schema 配置化

一、前沿

基于 Ant Design Vue 组件库实现了表单的配置化生成,通过 schema 配置化的方式实现表单的动态渲染、数据绑定和更新等功能,而提交按钮及获取数据逻辑由使用方自行提供。通过 schema 对象来定义表单的结构和属性,modelData 对象存储表单数据。主要组件包括 z-form-generatorformGeneratorGroup 以及各种具体的表单字段组件(如 field-datefield-radio 等)。

二、具体实现

1. schema 配置
  • 结构定义schema 对象包含 containers(表单结构的 JSON 数据)、colNum(最多展示列数)和 isViewType(表单是否为只读)等属性。containers 中可以包含多个组件配置,每个组件配置又有 typelabelmodel 等属性。
schema: {
  containers: [],
  colNum: 2,
  isViewType: false
}
  • 字段配置:不同类型的字段组件(如日期、单选、多选等)根据 schema 中的 type 属性来确定使用哪个具体的组件进行渲染。例如,type: 'date' 会使用 field-date 组件。
2. 组件渲染
  • formGeneratorGroup 组件:根据 schema 中的 type 属性动态渲染不同的表单字段组件。通过 getFieldType 方法 type 获取组件名称,并使用 JSX 进行渲染。
// formGeneratorGroup.js
const { getFieldType, field, colNum } = this
const comArr = ['area', 'checkbox', 'date', 'file', 'input', 'radio', 'search', 'select', 'upload', 'modal', 'cascader', 'list']
let isCom = _.includes(comArr, field.type)
const component = isCom ? getFieldType(field) : null
const { type, ...restProps } = field
return (
  <a-col>
    {
      component && <component
        schema={restProps}
        modelData={this.modelData}
        isViewType={this.isViewType}
        on-model-updated={this.onModelUpdated}
        on-error-updated={this.onErrorUpdated}
        on-schema-updated={this.onSchemaUpdated}
      />
    }
  </a-col>
)
  • 具体字段组件:每个字段组件(如 field-datefield-radio 等)根据 schema 中的属性进行渲染,并处理相应的事件(如 onChange)。
  getFieldType ({ type } = {}) {
    if (!type) {
      throw new Error('请确认组件类型')
    }
    return `Field-${type}`
  },
3. 组件化设计

采用组件化的设计思想,将不同类型的表单组件封装成独立的组件,如 FieldRadioFieldCheckboxFieldFile 等。每个组件都接收 schemamodelData 作为 props,通过 render 函数动态渲染表单元素。

// field-radio.vue
export default {
  name: 'FieldRadio',
  props: {
    schema: {
      type: Object,
      default: () => ({}),
      require: true,
    },
    modelData: {
      type: Object,
      default: () => ({}),
    },
  },
  methods: {
    changeHandle (e) {
      this.value = e.target.value
    },
  },
  render () {
    const { label, model, list, optionName, ...restSchema } = this.schema
    const { keyName: key, valueName: val } = {
      keyName: 'key',
      valueName: 'val',
      ...optionName,
    }
    return <a-form-model-item
      label={label}
      prop={model}
    >
      <a-radio-group
        value={this.value}
        prop={{ ...restSchema }}
        onChange={this.changeHandle}
      >
        <a-row>
          {
            list && list.map(el =>
              <a-col span={12}>
                <a-radio value={el[key]}>
                  {el[val]}
                </a-radio>
              </a-col>
            )
          }
        </a-row>
      </a-radio-group>
    </a-form-model-item>
  },
}
4. 数据绑定与更新

通过 modelData 对象实现表单数据的绑定。在组件中,通过 props 属性将 model 绑定到表单元素上,然后通过 $emit 触发自定义事件,将数据更新传递给父组件。

// field-radio.vue
methods: {
  changeHandle (e) {
    this.value = e.target.value
    this.$emit('model-updated', this.schema, this.value)
  },
}
5. 校验规则初始化

通过 initRules 方法初始化表单的校验规则。根据 schema 中的 required 属性和组件类型,为每个字段添加相应的校验规则。

// formGenerator.vue
initRules () {
  const { containers, rules } = this.cloneSchema
  // 初始化规则校验对象
  let initRules = { ...rules }
  // 平铺所有容器的fields
  const components = containers.reduce((acc, container) => {
    acc.push(...container.components);
    return acc;
  }, []);
  // 统一处理字段规则
  components.forEach(field => {
    const { code, type, required, inputType, regular, errorMessage, precision } = field;

    // 初始化当前字段的校验规则
    if (!initRules[code]) initRules[code] = [];
    // 兼容 required 历史数据
    if (required) {
      const requiredRule = type === 'list'
        ? { required: true, message: '该列表不得为空,请为列表新增数据' }
        : { required: true, message: '该项不得为空', trigger: type === 'date' ? 'change' : 'blur' };
      initRules[code].unshift(requiredRule);
    }

	// 如果是input类型组件,处理其校验规则
    if (type === 'input') {
      let ruleItem = initRules[code];

      // 处理内建的输入框类型校验
      if (inputType && ['phone', 'intNum', 'number', 'email', 'idCardNo', 'bussNo', 'bankNo'].includes(inputType)) {
		const { reg, message } = inputType === 'number' ? RulesReg[inputType][idx] : RulesReg[inputType]
        addValidationRule.call(this, ruleItem, reg, message)
      }

      // 处理自定义正则校验
      if (regular) {
        const reg = new RegExp(regular);
        const message = errorMessage;
        addValidationRule.call(this, ruleItem, reg, message)
      }

      initRules[code] = [...ruleItem];
    }
  })
 
  // 更新规则
  this.rules = initRules;
}

addValidationRule(ruleItem, reg, message) {
  ruleItem.push({
    validator: (rule, value, cb) => this.valitaRule(reg, value, cb, message),
    trigger: 'blur',
  });
}

三、特点

  1. 配置化设计:通过 schema 配置化的方式,实现了表单的动态生成和定制,提高了代码的可维护性和可扩展性。
  2. 组件化开发:将不同类型的表单组件封装成独立的组件(如 field-datefield-radio 等),提高了代码的复用性和可测试性。
  3. 动态渲染:根据 schema 中的 type 属性动态渲染不同的表单组件,实现了表单的灵活定制。
  4. 规则校验:支持多种类型的规则校验,包括必填项校验、输入框校验等,确保了用户输入数据的合法性。

相关文章:

  • @RequestParam、@RequestBody、@PathVariable
  • python 实现 A* 算法
  • AI日报 - 2025年3月16日
  • [测试]Selenium自动化测试常用函数
  • Java基础编程练习第31题-String类和StringBuffer类
  • 什么是 slot-scope?怎么理解。
  • 平安养老险深圳分公司积极开展2025年“3·15”金融消费者权益保护教育宣传活动
  • 19.如何使用 pandas 处理大型 Excel 文件:并行读取工作表
  • Spark 中创建 DataFrame 的2种方式对比
  • 【统计学相关笔记】抽样基本定理的证明
  • Linux与深入HTTP序列化和反序列化
  • 【LeetCode】622、设计循环队列
  • LuaJIT 学习(4)—— FFI 语义
  • JavaScript进阶篇:二、 对象与面向对象编程
  • 组合Ⅲ 力扣216
  • 卫语句优化多层if else嵌套
  • Typora最新版破解教程
  • 最新版VMware 17.6.3安装包分享
  • 功耗电流和耗电量的获取
  • 大数据 spark hive 总结
  • 杨国荣︱学术上的立此存照——《故旧往事,欲说还休》读后
  • 民生访谈|宝妈宝爸、毕业生、骑手……上海如何为不同人群提供就业保障
  • 跨海论汉|专访白馥兰:对中国农业史的兴趣,从翻译《齐民要术》开始
  • 新干式二尖瓣瓣膜国内上市,专家:重视瓣膜病全生命周期管理
  • 在上海生活8年,13岁英国女孩把城市记忆写进歌里
  • 杨荫凯已任浙江省委常委、组织部部长