本文志在经过合理的配置,能够增长或减小一行代码,就能轻松增长表单项。javascript
用element-ui的表单组件的时候,仍是有点不顺手。跟用表格的感受差不离,但优雅的使用 element-ui 中的 table 组件很棒的解决了这个问题。模仿这个,本身也简单的抽离了表单的配置。不过这并不必定适合全部的表单,具体状况具体使用吧。html
逻辑是:vue
首先看下,带有校验功能的form表单多数是这样,这里简单化表单只剩两个表单项。java
<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>
复制代码
通常的表单具有的条件有如下:element-ui
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是什么,什么类型的,校验方式如何,是否有默认值,有哪些选项之类的的等等,由此,表单配置项我是这样的:post
let formConfig = {
// category就是element里要用到的组件名,这里不能用type和component,后期要用,想不到合适的词就暂且用这个了
name:{label:'活动名称',category:'input',placeholder: `请输入活动名称`,default:'xxx',rules: [ { required: true, message: `活动名称不能为空`, trigger: "blur" } ]},
}
复制代码
后期若是须要增长一个表单项,或者修改一些配置,直接修改这里便可,再也不须要去各个地方修改。ui
先实现一个简单的表单:this
其实这个组件的封装须要的数据很明了,最重要的是上面的formConfig
,表单将会根据这个配置自动生成。spa
组件拿到formConfig
以后,首先要把model
和rules
抽离出来,而后循环formConfig
便可。code
<!-- 假设组件就叫 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>
复制代码
使用的话,以下:
<!-- 假设是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>
复制代码
上面的其实已经实现了,但此时若是忽然要增长表单项,好比想增长一个密码,很简单,直接修改formConfig便可,是否是很方便~
// <!-- 假设是views/Form.vue -->
let formConfig = {
// ...
// 这里是密码因此多了showPassword:true,其余表单项也是同样的,根据需求自由配置
password: { label: '密码', category: 'input',showPassword:true, placeholder: `请输入密码`, rules: [ { required: true, message: `密码不能为空`, trigger: 'blur' } ], style: { width: '300px' } }
}
复制代码
其实这个简单,父组件在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和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" 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">
<!-- 文本框 类-->
<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]" >
<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]" >
<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]" >
<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>
复制代码