抽离配置,几分钟快速创建和修改表单

简介: 抽离配置,几分钟快速创建和修改表单

抽离配置,几分钟快速创建和修改表单


本文志在通过合理的配置,可以增加或减少一行代码,就能轻松增加表单项。

用element-ui的表单组件的时候,还是有点不顺手。跟用表格的感觉差不离,但优雅的使用 element-ui 中的 table 组件很棒的解决了这个问题。模仿这个,自己也简单的抽离了表单的配置。不过这并不一定适合所有的表单,具体情况具体使用吧。

逻辑是:

  1. 将el-form封装成一个组件
  2. 将表单的配置项传给这个组件,生成相应的表单。

没有封装前的form

首先看下,带有校验功能的form表单多数是这样,这里简单化表单只剩两个表单项。

<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
  <el-form-item label="活动名称" prop="name">
    <el-input v-model="ruleForm.name"></el-input>
  </el-form-item>
  <el-form-item label="活动区域" prop="region">
    <el-select v-model="ruleForm.region" placeholder="请选择活动区域">
      <el-option label="区域一" value="shanghai"></el-option>
      <el-option label="区域二" value="beijing"></el-option>
    </el-select>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
    <el-button @click="resetForm('ruleForm')">重置</el-button>
  </el-form-item>
</el-form>
<script>
  export default {
    data() {
      return {
        ruleForm: {
          name: '',
          region: '',
        },
        rules: {
          name: [
            { required: true, message: '请输入活动名称', trigger: 'blur' },
            { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
          ],
          region: [
            { required: true, message: '请选择活动区域', trigger: 'change' }
          ]
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
    }
  }
</script>

一般的表单具备的条件有以下:

  • el-form本身绑定一个model,{name:'',region:''},里面的属性就是每个表单项将要绑定的
  • el-form上有个方便校验规则的属性rules,{name: [ { required: true, message: '请输入活动名称', trigger: 'blur' }], region: [ { required: true, message: '请选择活动区域', trigger: 'change' } ]}
  • el-form上还有ref,在点击提交表单的时候也是用于校验
  • el-form上还有其他属性的设置,label宽度,对齐方式之类的
  • el-form-item每个必有label属性和prop属性,prop就是model的键名,各个表单元素上面有各自的配置

先抽离表单配置

由此,总结一个表单的配置项:model,rules,ref,attrsOther。

但是一般我们接到一个表单的需求,通常关注点是,这个表单项的label是什么,什么类型的,校验方式如何,是否有默认值,有哪些选项之类的的等等,由此,表单配置项我是这样的:

let formConfig = {
  // category就是element里要用到的组件名,这里不能用type和component,后期要用,想不到合适的词就暂且用这个了
  name:{label:'活动名称',category:'input',placeholder: `请输入活动名称`,default:'xxx',rules: [ { required: true, message: `活动名称不能为空`, trigger: "blur" } ]},
}

后期如果需要增加一个表单项,或者修改一些配置,直接修改这里即可,不再需要去各个地方修改。

具体实现组件的操作

先实现一个简单的表单:

其实这个组件的封装需要的数据很明了,最重要的是上面的formConfig,表单将会根据这个配置自动生成。

组件拿到formConfig之后,首先要把modelrules抽离出来,然后循环formConfig即可。

1. 实现组件

<!-- 假设组件就叫 EnhancedForm.vue -->
<template>
  <!-- v-bind会自动将form的配置属性赋值过来,特别棒的一个指令 -->
  <el-form :model="form.props" :rules="form.rules" >
    <!-- 表单的每项都是一个组件,用法参照 https://element.eleme.cn/#/zh-CN/component/form -->
    <el-form-item v-for="(config, prop) in form.configs" :label="config.label" :key="prop" :prop="prop">
      <!-- 如果使用的组件是el-input才会是这样,每个表单项的配置可能不一样,但没关系,有v-bind -->
      <el-input v-if="config.category === 'input'" v-model="form.props[prop]" v-bind="config">
      </el-input>
      <!-- 如果使用的组件是el-select才会是这样 -->
      <el-select v-if="config.category === 'select'" v-model="form.props[prop]" >
        <el-option v-for="item in config.options" :key="item.value" :value="item.value" :label="item.label" ></el-option>
      </el-select>
    </el-form-item>
  </el-form>
</template>
<script>
export default {
  props: ['formConfig'],
  data () {
    let form = {
      configs: this.formConfig,
      // el-form的model的值
      props: {},
      rules: {}
    }
    Object.keys(this.formConfig).forEach(prop => {
      // 这里如果设置了默认项就是默认值,没有就是undefined
      form.props[prop] = this.formConfig[prop].default
      form.rules[prop] = this.formConfig[prop].rules
    })
    return {
      form
    }
  }
}
</script>

2. 引用组件

使用的话,如下:

<!-- 假设是views/Form.vue -->
<template>
  <div>
    <enhanced-form :form-config="formConfig"></enhanced-form>
  </div>
</template>
<script>
import EnhancedForm from '../components/EnhancedForm.vue'
export default {
  components: { EnhancedForm },
  data () {
    let formConfig = {
      // category就是element里要用到的组件名,这里不能用type和component,后期要用,想不到合适的词就暂且用这个了
      name: { label: '活动名称', category: 'input', placeholder: `请输入活动名称`, rules: [ { required: true, message: `活动名称不能为空`, trigger: 'blur' } ], style: { width: '300px' } },
      region: { label: '活动区域', category: 'select', default: 2, options: [{ label: '南京', value: 1 }, { label: '北京', value: 2 }], rules: [ { required: true, message: `请选择活动区域`, trigger: 'change' } ] }
    }
    return {
      formConfig
    }
  }
}
</script>

3. 增加表单项

上面的其实已经实现了,但此时如果突然要增加表单项,比如想增加一个密码,很简单,直接修改formConfig即可,是不是很方便~

// <!-- 假设是views/Form.vue -->
    let formConfig = {
      // ...
      // 这里是密码所以多了showPassword:true,其他表单项也是一样的,根据需求自由配置
      password: { label: '密码', category: 'input',showPassword:true, placeholder: `请输入密码`, rules: [ { required: true, message: `密码不能为空`, trigger: 'blur' } ], style: { width: '300px' } }
    }

父组件怎么拿到form的所有数据

其实这个简单,父组件在enhanced-form标签上设置ref的属性,然后通过this.$refs.xx.$data.form.props就可以拿到所有表单项的数据(其实可以通过ref拿到子组件所有的信息~~):

<!-- 假设是views/Form.vue -->
<template>
  <div>
    <enhanced-form ref="demoForm" :form-config="formConfig"></enhanced-form>
    <el-button @click="handleClick"> 点吖 </el-button>
  </div>
</template>
<script>
import EnhancedForm from '../components/EnhancedForm.vue'
export default {
  components: { EnhancedForm },
  // data () { ....},
  methods: {
    handleClick () {
      console.log(this.$refs.demoForm.$data.form.props)
    }
  }
}
</script>

咦,自动检测呢

嘿,自动检测还没实现呢!其实也不难呐,这里因为需要ref,所以,在传入子组件的时候,除了有formConfig,可以增加formAttr是给form增加自身的属性,比如ref/labelWidth/labelPosition等等

<!-- EnhancedForm.vue -->
<el-form :model="form.props" :rules="form.rules" v-bind="form.attrs">
<script>
  props: ['formConfig', 'formAttr'],
  data () {
    let form = {
      // ...
      attrs: this.formAttr,
    }
</script>
<!-- Form.vue -->
<enhanced-form ref="demoForm" :form-config="formConfig" :form-attr="formAttr"></enhanced-form>
<script>
    data(){
      // ...
      let formAttr = {
        ref: 'hiForm',
        labelWidth: '80px'
      }
      return {
        formConfig,
        formAttr
      }
    }
    handleClick () {
      console.log(this.$refs.demoForm.$data.form.props)
      this.$refs.demoForm.$refs[this.formAttr.ref].validate(valid => {
        console.log(valid)
      })
    }
</script>

特殊需求的表单项,用slot

上面都是正常的,如果有特殊需求的,可以插入slot和component。这里演示slot

<!-- EnhancedForm.vue -->
    <template  v-for="(config, prop) in form.configs" >
      <slot v-if="config.slotName" :name="config.slotName" v-bind:form="form" v-bind:config="config"></slot>
      <!-- 表单的每项都是一个组件,用法参照 https://element.eleme.cn/#/zh-CN/component/form -->
      <el-form-item v-else :label="config.label" :key="prop" :prop="prop">
<enhanced-form ref="demoForm" :form-config="formConfig" :form-attr="formAttr">
      <template v-slot:desc="{config,form}">
        <el-form-item :label="config.label" prop="desc">
          <el-input v-model="form.props.desc" v-bind="config"></el-input>
        </el-form-item>
      </template>
    </enhanced-form>
<script>
    let formConfig = {
      // ...
      // slotName有这个属性的表示是slot,注意这里不能叫slot不然后期v-bind会冲突。
      desc: { slotName: 'desc', label: '评价', category: 'input', placeholder: `请输入评价`, rules: [ { required: true, message: `评价不能为空`, trigger: 'blur' } ], style: { width: '300px' } }
    }
</script>


升华

实际项目中,当然不可能只是input和select,但举一反三,其他也一样的配置。这里是我自己的配置,还有一部分并未放进去,根据需求自己可以再修改,以下仅供参考。

<template>
  <!-- v-bind会自动将form的配置属性赋值过来,特别棒的一个指令 -->
  <el-form :model="form.props" :rules="form.rules" v-bind="form.attrs">
    <template  v-for="(config, prop) in form.configs" >
      <slot v-if="config.slotName" :name="config.slotName" :form="form" :config="config"></slot>
      <!-- 表单的每项都是一个组件,用法参照 https://element.eleme.cn/#/zh-CN/component/form -->
      <el-form-item v-else :label="config.label" :key="prop" :prop="prop">
        <!-- 文本框 类-->
        <component v-if=" config.category === 'input' || config.category === 'input-number' || config.category === 'time-picker' || config.category === 'date-picker' " :is="'el-' + config.category" v-model="form.props[prop]" :key="config.component" v-bind="config" ></component>
        <!-- 选择框类 -->
        <el-radio-group v-if="config.category === 'radio-group'" v-model="form.props[prop]" v-bind="config">
          <el-radio v-for="item in config.options" :key="item.value" :label="item.value" >{{ item.label }}</el-radio >
        </el-radio-group>
        <el-checkbox-group v-if="config.category === 'checkbox-group'" v-model="form.props[prop]" v-bind="config">
          <el-checkbox v-for="item in config.options" :key="item.value" :label="item.value" >{{ item.label }}</el-checkbox >
        </el-checkbox-group>
        <el-select v-if="config.category === 'select'" v-model="form.props[prop]" v-bind="config">
          <el-option v-for="item in config.options" :key="item.value" :value="item.value" :label="item.label" ></el-option>
        </el-select>
      </el-form-item>
    </template>
  </el-form>
</template>
<script>
export default {
  props: ['formConfig', 'formAttr'],
  data () {
    let form = {
      configs: this.formConfig,
      attrs: this.formAttr,
      // el-form的model的值
      props: {},
      rules: {}
    }
    Object.keys(this.formConfig).forEach(prop => {
      // 这里如果设置了默认项就是默认值,没有就是undefined
      form.props[prop] = this.formConfig[prop].default
      form.rules[prop] = this.formConfig[prop].rules
    })
    return {
      form
    }
  }
}
</script>


目录
相关文章
|
2月前
|
前端开发 JavaScript UED
react或者vue更改用户所属组,将页面所有数据进行替换(解决问题思路)____一个按钮使得页面所有接口重新请求
在React或Vue中,若需在更改用户所属组后更新页面所有数据但不刷新整个页面,可以通过改变路由出口的key值来实现。在用户切换组成功后,更新key值,这会触发React或Vue重新渲染路由出口下的所有组件,从而请求新的数据。这种方法避免了使用`window.location.reload()`导致的页面闪烁,提供了更流畅的用户体验。
56 1
react或者vue更改用户所属组,将页面所有数据进行替换(解决问题思路)____一个按钮使得页面所有接口重新请求
|
4月前
|
开发框架 JavaScript 前端开发
基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式
基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式
|
4月前
|
JavaScript
文本,视频网站提交的方法,配置提交的按钮,一次性提交的方法,Vue编写好代码向后台发送数据就行
文本,视频网站提交的方法,配置提交的按钮,一次性提交的方法,Vue编写好代码向后台发送数据就行
|
4月前
|
前端开发 NoSQL JavaScript
若依修改---重新部署项目注意事项,新文件初始化需要修改的地方,打包后的文件很难进行修改,如果想要不断修改项目,注意保存原项目,才可以不断修改,前端:在Vue.config.js文件中修改target
若依修改---重新部署项目注意事项,新文件初始化需要修改的地方,打包后的文件很难进行修改,如果想要不断修改项目,注意保存原项目,才可以不断修改,前端:在Vue.config.js文件中修改target
|
4月前
|
前端开发 JavaScript Java
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
|
6月前
|
JavaScript
vue列表信息展示中新增数据,与编辑数据页面复用,降低重复代码
vue列表信息展示中新增数据,与编辑数据页面复用,降低重复代码
273 2
|
6月前
|
移动开发 前端开发 JavaScript
动态获取新增的数据+项目实例介绍
动态获取新增的数据+项目实例介绍
91 0
|
6月前
|
JavaScript
vue开发过程中,修改了数据,但是页面死活不渲染改变!没变化!怎么办?6种方法解决~
vue开发过程中,修改了数据,但是页面死活不渲染改变!没变化!怎么办?6种方法解决~
|
JavaScript 前端开发
如何阻止在 vue项目中快速双击俩次新增/编辑连续发送俩次请求
如何阻止在 vue项目中快速双击俩次新增/编辑连续发送俩次请求
89 0
|
JavaScript
fastadmin 自定义 按钮 动态切换数据 TAB切换
fastadmin 自定义 按钮 动态切换数据 TAB切换
282 0