Bootstrap

Vue2 element-ui组件二封-表单组件-效果展示

vue2已经落后了? 不着急, vue3的也在写的过程中, 只是发出来vue2的一些组件

系列说明:

编写原因

vue2在很多人眼里已经快过时了, 而我一直想写一些总结, 但是从两年前到现在都因为各种原因搁置了. 掘金上好多前辈都分享了使用json来配置表单的方式, 但是json对于复杂表单有些无力, 且不方便debug, 我也分享一下我的方式, 欢迎各位前辈指导.

编码规范

vue2即将寿终正寝, 故而不会太遵守规范. 当然如果有规范问题也希望各位指出. 将在vue3的专栏中修改

更新频率

目前没有固定频率, 毕竟我也是第一次写这种文章, 如果读者有兴趣, 我会尽力更新的, 快的话大概每周一篇. 目前我的文章表达能力较差, 如果有这方面的指导, 同样感激不尽.

效果预览

每次文章发布后, 我将同步代码到此仓库, 代码后方会附上代码位置
github: https://github.com/ly-chn/element-ui-decorator-demo

还会有什么系列

列表系列, table相关组件, 再然后就是vue3的了

表单系列目的: 替换原有编码方式为下方方式

样式展示:

图片.png

原有编码表单:

效果位置: https://ly-chn.github.io/element-ui-decorator-demo/#/example/form

代码位置: https://github.com/ly-chn/element-ui-decorator-demo/blob/main/src/views/form/simple-form.vue

封装的目标写法:

<template>
  <div>
    <ly-form ref="form" half>
      <ly-input label="姓名" v-model="form.fullName" :rules="[$rules.must, $rules.chinese(2, 4)]"/>
      <ly-radio label="政治面貌" v-model="form.politicalStatus" dict-code="sys_political_status" :rules="$rules.must"/>
      <ly-input label="手机号" v-model="form.mobilePhone" :rules="[$rules.must, $rules.mobilePhone]"/>
      <ly-input label="身份证号" v-model="form.idCard" :rules="[$rules.must, $rules.idCard]"/>
      <ly-date-picker label="出生日期" v-model="form.birthday" :rules="$rules.must"/>
      <ly-select label="职业" v-model="form.jobType" dict-code="sys_job_type" :rules="$rules.must"/>
      <ly-textarea label="个人介绍" v-model="form.introduction" maxlength="100" :rules="$rules.must"/>
      <el-col>
        <el-button type="primary" @click="handleSubmit">提交</el-button>
        <el-button @click="handleReset">重置</el-button>
      </el-col>
    </ly-form>
  </div>
</template>

<script>
export default {
  name: "tmp",
  data() {
    return {
      form: {
        // 姓名
        fullName: undefined,
        // 政治面貌
        politicalStatus: undefined,
        // 手机号
        mobilePhone: undefined,
        // 身份证号
        idCard: undefined,
        // 生日
        birthday: undefined,
        // 职业
        jobType: undefined,
        // 个人介绍
        introduction: undefined
      },
    }
  },
  methods: {
    async handleSubmit() {
      await this.$refs.form.validate()
      this.$message.success('验证通过')
    },
    handleReset() {
      this.$refs.form.resetFields()
    },
  }
}
</script>

解释(简单介绍上述demo用到的功能):

  • ly-form

作为ElForm+ElRow的二封, half作为span的另一种配置, 即表单项的span默认值, 去除model参数, 并将rules改写到表单项中

validateFields函数为了代码简洁, 去掉参数中回调函数, 仅返回promise

由于表单项没有了props参数, 因此validateFields函数不再支持校验指定字段, 可以通过表单项的validate函数单独校验

  • ly-input

<ly-input label="姓名" v-model="form.fullName" :rules="[$rules.must, $rules.chinese(2, 4)]"/>

作为ElCol+ElFormItem+ElInput的二封, label对应ElFormItem的label, v-model作用于ElInput, rules对应ElFormItem的rules

同时, 表单项无需填写prop参数, 避免复制粘贴时出现不友好的情况

rules调整规则:

  • 如果非数组, 则转为数组
  • 如果是函数, 则执行函数
  • 如果是$rules.must函数, 则根据label, placeholder等函数生成此函数的第一个参数
    $rules.must实现见最下方(各公司有所差异, 仅供参考)
  • ly-radio / ly-select

其实很多项目都有自己的字典库设计, 所以都有字典编码(dict-code)这个概念
当前项目的字典项格式:

type LyDictItem = {
  // 显示的文字
  label: string
  // 值
  value: string
  // 字典项说明,会显示给前端
  desc?: string
  // 渲染时, tag type
  type?: string
}

有几种差不多的方案, 本次示例仅使用最后一种做演示(减少封装复杂度, 否则需要vue-router处代码处理逻辑)

  • 路由拦截中, 前端获取所有字典, 放到vuex/pinia
  • 路由拦截中, 前端获取所有字典, 放到localStorage/sessionStorage/indexDB等位置
  • 前端按需通过http获取
  • 前端按需通过http获取, 并缓存, 添加过期时间限制
  • ly-date-picker

日期/时间/日期时间范围选择器, v-model对应的值始终为字符串, 避免http交互时二次转换

范围选择器(时间范围/数字范围等)同时支持v-model(数组)和from.sync(最小值)+to.sync(最大值)

  • ly-textarea

input在业务中, type一般只有text/textarea两种类型

但是text和text-area参数/使用场景区别较大, 故而直接分成两个组件, 去掉type参数

如填写maxlength属性, 自动将show-word-limit设置为true

must(message = '请录入此项') {
  return {
    required: true,
    validator: (rule, value, callback) => {
      if (['number', 'boolean'].includes(typeof value)) {
        return callback()
      }
      if (typeof value === 'string') {
        value = value.trim()
      }
      callback(value && value.length ? undefined : message)
    },
    trigger
  }
}

end

感谢各位观看, 但愿没有浪费各位时间, 如果浪费, 请各位尽情发泄

计划:

  • ly-form : ElForm+ElRow
  • el-form-item-extends: ElFormItem功能拓展
  • ly-form-item : ElCol+ELFormItem
  • ly-input: LyFormItem+ElInput
  • ly-select: LyFormItem+ElSelect

后续待定

;