在项目中,表单作为用户输入占用很重要的一部分,目前的前端框架,基本对表单进行了一些简单的封装,如果输入项很多,以iview为例,会有一大堆的类似:
<FormItem label="Input"> ? ? ? ? ? ? <Input v-model="formItem.input" placeholder="Enter something..."></Input></FormItem>
这样的标签,现在将用
{//input输入框
type:'InputNumber',
placeholder:"请数量",
label:'数量',
value:1,
props:'num',
isRequire:true,
emptyTip:'数量不能为空'
},
这样的输入来简化,配置表单的生成。
一、构建myform组建
新建myForm.vue文件
1、结合vue和iveiw的框架,根据需求,对表单分一列,两列,多列展示,需要设置变量cols,表单项前面的文字宽度也不一样,因此还需设置变量labelWidth,渲染表单(展示你想展示的内容),需设置变量formDatas,最后,用户完成输入后还需获取表单数据,需要设置变了formDataModel。到此,配置表单大致需要的变量已基本设置完成。
大致代码如下:
<Form ref="formValidate" :label-width="labelWidth" :model="formDataModel" class="leftLabel"> ? ? <Row :gutter="32"> ? ? ? <Col :span="cols" v-for="(item,index) in formDatas" :key="index"> ? ? ? ? <myFormItem ?:schema = "item" :key="index" :formObj="formDatas"></myFormItem> ? ? ? </Col> ? ? </Row> </Form>
2、一般情况下每个表单的下面都会有操作,比如确定,取消等,这样我们可以用slot插入来实现不同引用页面的功能
<section> ? ? ? <slot name="btnCancel" :cancelFormBtn="cancelForm"><Button type="default">取消</Button></slot> ? ? ? <slot name="btnSave" :saveFormBtn="saveForm"><Button type="primary">确定</Button></slot> </section>
这样myform组件就大致完成,在上面的myform组建中,有一个myFormItem 的组建,下面我们就来实现myFormItem。
二、构建myFormItem组建
新建myFormItem.vue文件
myFormItem中,由于表单项有很多种,包括input,select,checkBox等,如果在这个组建中用v-if来控制显示,这样这个页面很臃肿,因此,采用函数式组建来和render函数来动态构建不同类型的表单
因此myFormItem组建代码大致如下:
<my-contrl :schema="schema" :formObj="formObj"></my-contrl>
三、构建函数式组件mycontrl组件
新建myContrl.js文件
函数式组件的大致结构如下,首先根据context中的类型进行分发,然后再用渲染函数渲染出来
function getControl(context){
?? ?let {type,label,placeholder,value} = context.props.shema;
?? ?return {type,label,placeholder,value}
}
export default{
?? ?functional:true,
?? ?props:{
?? ?schema:Object
?? ?},
?? ?render(h,context){
?? ??? ?let {type,label,placeholder,value} = getControl(context);
?? ? ? ?return h('FormItem',{
?? ? ? ??? ??? ? props:{
? ? ? ? ?? ??? ??? ?label:label,
? ? ? ?? ??? ??? ??? ?},
?? ? ? ? ? },[
?? ? ? ??? ?h(type,{
?? ? ? ??? ?placeholder:placeholder,
? ? ??? ??? ?value:value,
?? ? ? ??? ?})
?? ? ? ?])
?? ?}
}
中间需注意的小细节:
1、由于一般设置必填项和非必填项的样式不一致,如果要用到iview里面的样式,需要在formItem下加class:‘ivu-form-item-required’,代码如下:
class:{
? ? ? ? 'ivu-form-item-required':isRequire,
? ? ? },
2、如果表单项是select,checkBox等,在select下面会有option属性,因为都是动态输入的值,所以,要用render函数动态生成数组
keyValue.map(item=>{
? ? ? ? return h(keyData,{
? ? ? ? ? props:{
? ? ? ? ? ?[keyData==='Option'?'value':keyData==='Button'?'icon':'label']:item.key,
? ? ? ? ? }
? ? ? ? },item.label)
? ? ? })
到此,静态页面的渲染也就完成了。
四、用户输入的时候需要对表单项中进行各种验证或者逻辑
为了实现此功能,一般我们用到vue中的混入,将公用的验证,逻辑写到同一个文件中,再将每个表单中单独的逻辑放到引用这个表单的vue中。
因此在mycontrl.js文件的render函数中,要为每个表单项注册一个on-change或on-blur事件,然后触发对应的函数,并且设置此表单的对象的值。
1、设置表单项的值
context.parent.setValue(context.data.attrs.formObj,props,val);
2、判断是否必填进行操作
if(val==='' || val===null || val.length===0){
? ? context.parent.Validate('rule-empty',`${label}id`,emptyTip);
? ? ?return;
? ?}else{
? ? ?context.parent.ValidateHide('rule-empty',`${label}id`)
}
3、规则验证判断
for(let r = 0;r<rules.length;r++){
?let flag = rules[r].valide(val);
? if(flag){
? ?context.parent.ValidateHide(`rule-${rules[r].name}`,`${label}id`)
? ? }else{
? ? context.parent.Validate(`rule-${rules[r].name}`,`${label}id`,rules[r].tip);
? ? ?break;
? ?}
? }
?return;
4、逻辑判断
logicRelation(val)
像类似前面的Validate,ValidateHide,setValue这些函数,都放在混入的js函数中,作为公共函数,而逻辑,规则下的验证函数就放在了每个配置表单的配置项里面了。以上所有的判断都写作on-blur或on-change中
五、表单输入完成获取表单中的值
这个写在myForm.vue中
1、在计算属性中,取得这个表单的项和值
computed:{
?? ?formDataModel:function(){
?? ?return this.getValue(this.formDatas);
? ? ? }
? ?}
2、点击确定按钮的时候,将这个值返回到传入确定按钮的这个函数中
?? ?saveForm(fn,errFn){
? ? ? ? let _this = this;
? ? ? ? if(_this.isValidData(_this.formDatas,_this.formDataModel)){
? ? ? ? ? fn(_this.formDataModel)
? ? ? ? }else{
? ? ? ? ? _this.$Message.error('表单输入有误!请按页面提示输入')
? ? ? ? ? if(errFn){
? ? ? ? ? ? errFn()
? ? ? ? ? }
? ? ? ? }
? ? ? }
3、取消按钮,将值还原,或者是别的需要的操作
cancelForm(type,fn){
? if(type==='modify'){
? ? fn()
?}else if(type==='close'){
?this.$emit('closeModel')
? }else{
? ?this.backDefault(this.defaultValCopy,this.formDatas);
? }
}
六、在要用到表单的页面使用
?? ??? ?<my-form :formData="formDatas" :cols="12" :labelWidth="100">
? ? ? ? ? ? <template v-slot:btnCancel ="{cancelFormBtn}">
? ? ? ? ? ? ? <Button type="default" @click="cancelFormBtn('modify',getlist)">取消</Button>
? ? ? ? ? ? </template>
? ? ? ? ? ? <template v-slot:btnSave ="{saveFormBtn}" >
? ? ? ? ? ? ? <Button type="primary" @click="saveFormBtn(save)">保存</Button>
? ? ? ? ? ? </template>
? ? ? ? ?</my-form>
配置项中的formData格式
? ? ? ?[ {
? ? ? ? ? ? type:'InputNumber',
? ? ? ? ? ? placeholder:"Web",
? ? ? ? ? ? label:'Web',
? ? ? ? ? ? value:1,
? ? ? ? ? ? props:'web',
? ? ? ? ? ? isRequire:true,
? ? ? ? ? ? emptyTip:'Web不为空'
? ? ? ? ? },
? ? ? ? ? {//select选择框
? ? ? ? ? ? type:'Select',
? ? ? ? ? ? placeholder:"请选择要输入内容",
? ? ? ? ? ? label:'记录',
? ? ? ? ? ? data:{
? ? ? ? ? ? ? Option:[
? ? ? ? ? ? ? {key:'1',label:'记录'},
? ? ? ? ? ? ? {key:'0',label:'不记录'},
? ? ? ? ? ? ]
? ? ? ? ? ? },
? ? ? ? ? ? value:'1',
? ? ? ? ? ? props:'record',
? ? ? ? ? ? isRequire:true,
? ? ? ? ? ? emptyTip:'请选择',
? ? ? ? ? ? logicRelation:this.isHideKafka
? ? ? ? ? }]
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于vue和iview结合动态生成表单实例的详细内容...